<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/feed/styles.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Mohammad Abu Mattar | Blog</title><description>The latest Blog from Mohammad Abu Mattar.</description><link>https://mkabumattar.com/</link><item><title>Testing Terraform: Static Analysis, Native Tests, and Terratest</title><link>https://mkabumattar.com/blog/post/terraform-testing-terratest-native-tests/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/terraform-testing-terratest-native-tests/</guid><description>A practical testing strategy for Terraform modules: the testing pyramid, tflint static analysis, native terraform test with provider mocking, Terratest integration tests in Go, safe teardown, and a GitHub Actions pipeline with OIDC.</description><pubDate>Mon, 20 Jul 2026 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you treat infrastructure as code, you have to test it like code. Most of us have lived the alternative. You change one input on a shared module, run a quick plan against staging, and merge. A few hours later you learn that the harmless change replaced a database because of a dependency you did not see in the plan. Manual review and eyeballing plan output do not catch that class of regression. Infrastructure needs an automated testing strategy, and Terraform now gives you enough tooling to build a real one.&lt;/p&gt;
&lt;h2&gt;Why infrastructure code needs testing&lt;/h2&gt;
&lt;p&gt;Application teams lean on automated tests to catch regressions before a merge. Infrastructure teams often lean on intuition and a manual deploy check instead, which gives you slow feedback and fragile environments.&lt;/p&gt;
&lt;p&gt;Testing infrastructure validates your logic, blocks misconfigurations, and speeds up review. Good tests also double as documentation: if someone edits a routing module next year, the tests tell them immediately when they break network isolation. The point is confidence that the code does what you expect, even as provider versions bump and cloud APIs shift under you.&lt;/p&gt;
&lt;h2&gt;The Terraform testing pyramid&lt;/h2&gt;
&lt;p&gt;Infrastructure testing works best as a pyramid, same as application testing. The base is fast and cheap and runs constantly. As you move up, tests get more thorough but cost more time and money.&lt;/p&gt;
&lt;p&gt;&lt;DrawIO
  client:load
  src=&quot;/assets/blog/0108-terraform-testing-terratest-native-tests/testing-pyramid.drawio&quot;
  title=&quot;The Terraform testing pyramid&quot;
  caption=&quot;Static analysis at the base runs in milliseconds for free. Unit tests with mocked providers run in seconds. Integration tests with Terratest cost real minutes and real cloud money, so you run fewer of them.&quot;
  height={440}
/&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Layer&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Tools&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Speed&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Cost&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Static analysis&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;terraform validate&lt;/code&gt;, &lt;code&gt;tflint&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;ms&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;free&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Syntax, naming, missing vars, provider rules, no cloud calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Unit tests&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;native &lt;code&gt;terraform test&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;seconds&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;free&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Inputs, outputs, conditional logic with mocked providers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Integration&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Terratest (Go)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;minutes&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;cloud fees&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Provision real resources and confirm the cloud accepts them&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A real strategy uses all three: catch syntax on your machine, validate logic in the pull request, and verify a true deployment before you tag a module version.&lt;/p&gt;
&lt;h2&gt;Static analysis: catch errors before the cloud does&lt;/h2&gt;
&lt;p&gt;The base of the pyramid parses your config and looks for problems without ever calling your provider.&lt;/p&gt;
&lt;p&gt;Start with &lt;code&gt;terraform validate&lt;/code&gt;. It checks syntax, confirms required arguments are present, and makes sure variable references resolve. It has limits, though: it does not know whether an instance type actually exists or whether your tags follow policy.&lt;/p&gt;
&lt;p&gt;For the deeper checks, add &lt;code&gt;tflint&lt;/code&gt;, a pluggable linter that inspects provider-specific rules. It catches things like an invalid EC2 instance type or deprecated syntax that basic validation misses. Configure it with a &lt;code&gt;.tflint.hcl&lt;/code&gt; at the repo root:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;plugin &amp;quot;terraform&amp;quot; {
  enabled = true
  preset  = &amp;quot;recommended&amp;quot;
}

plugin &amp;quot;aws&amp;quot; {
  enabled = true
  version = &amp;quot;0.30.0&amp;quot;
  source  = &amp;quot;github.com/terraform-linters/tflint-ruleset-aws&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Keep the fast checks one command away locally so you run them without thinking:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;terraform fmt -recursive
terraform init -backend=false   # no remote state needed just to validate
terraform validate
tflint --init &amp;amp;&amp;amp; tflint -f compact
&lt;/code&gt;&lt;/pre&gt;
&lt;Notice type=&quot;tip&quot;&gt;&lt;p&gt;Run &lt;code&gt;terraform init -backend=false&lt;/code&gt; for validation and unit tests. It fetches providers and modules so the config can be evaluated, without touching remote state or needing cloud credentials.&lt;/p&gt;
&lt;/Notice&gt;&lt;h2&gt;Unit tests with native &lt;code&gt;terraform test&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;For years, testing Terraform meant reaching for a third-party tool. That changed in Terraform 1.6, which added a native test framework, followed by provider mocking in 1.7. Native tests use HCL, so you do not learn a new language just to test a module.&lt;/p&gt;
&lt;p&gt;Tests live in files ending in &lt;code&gt;.tftest.hcl&lt;/code&gt;, and &lt;code&gt;terraform test&lt;/code&gt; discovers them automatically. A common layout keeps them in a &lt;code&gt;tests/&lt;/code&gt; directory next to the module:&lt;/p&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;modules/&lt;ul&gt;
&lt;li&gt;s3-bucket/&lt;ul&gt;
&lt;li&gt;main.tf&lt;/li&gt;
&lt;li&gt;variables.tf&lt;/li&gt;
&lt;li&gt;outputs.tf&lt;/li&gt;
&lt;li&gt;tests/&lt;ul&gt;
&lt;li&gt;bucket_naming.tftest.hcl&lt;/li&gt;
&lt;li&gt;bucket_mocked.tftest.hcl&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;p&gt;Here is a unit test for a module that builds an S3 bucket name from variables. Because it is a unit test, we do not want to create anything, so &lt;code&gt;command = plan&lt;/code&gt; runs the plan in memory and we assert against the planned values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;variables {
  bucket_prefix = &amp;quot;my-application&amp;quot;
  environment   = &amp;quot;prod&amp;quot;
}

run &amp;quot;validates_bucket_name_format&amp;quot; {
  command = plan

  assert {
    condition     = aws_s3_bucket.main.bucket == &amp;quot;my-application-prod-bucket&amp;quot;
    error_message = &amp;quot;The S3 bucket name did not match the expected naming convention.&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;terraform test&lt;/code&gt; builds the plan and evaluates each &lt;code&gt;assert&lt;/code&gt;. If a condition is false, the run fails and prints your message. You can also assert on outputs with a full apply when you want to check computed values that only exist after creation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;run &amp;quot;exposes_bucket_arn_output&amp;quot; {
  command = apply

  assert {
    condition     = can(regex(&amp;quot;^arn:aws:s3:::&amp;quot;, output.bucket_arn))
    error_message = &amp;quot;bucket_arn output is not a valid S3 ARN.&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Mock providers so tests need no cloud credentials&lt;/h2&gt;
&lt;p&gt;A plan still authenticates to the provider to refresh state and read schemas. To run fully offline, or in CI without credentials, use &lt;code&gt;mock_provider&lt;/code&gt;. It returns the real provider schema but generates fake data for computed attributes instead of calling the cloud.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;mock_provider &amp;quot;aws&amp;quot; {
  override_during = plan # generate mock values during the plan phase
}

variables {
  bucket_prefix = &amp;quot;test&amp;quot;
  environment   = &amp;quot;dev&amp;quot;
}

run &amp;quot;test_with_mocks&amp;quot; {
  command = plan

  assert {
    condition     = aws_s3_bucket.main.bucket == &amp;quot;test-dev-bucket&amp;quot;
    error_message = &amp;quot;Bucket name mismatch under mocks.&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With mocks, Terraform fills computed attributes with placeholders: &lt;code&gt;0&lt;/code&gt; for numbers, &lt;code&gt;false&lt;/code&gt; for booleans, and a random 8-character string for strings. When your logic depends on a specific computed value, pin it with &lt;code&gt;override_resource&lt;/code&gt; so the assertion is deterministic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;run &amp;quot;uses_known_arn&amp;quot; {
  command = plan

  override_resource {
    target = aws_s3_bucket.main
    values = {
      arn = &amp;quot;arn:aws:s3:::my-application-prod-bucket&amp;quot;
    }
  }

  assert {
    condition     = aws_s3_bucket.main.arn == &amp;quot;arn:aws:s3:::my-application-prod-bucket&amp;quot;
    error_message = &amp;quot;The overridden ARN was not used.&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Integration tests with Terratest in Go&lt;/h2&gt;
&lt;p&gt;Unit tests are fast, but they cannot promise the cloud will accept your config. A plan can pass and still fail on apply because of an IAM permission, a quota, or an API constraint. For real confidence you provision actual resources, check them, and tear them down. Terratest is the standard tool for that, and it runs in Go.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package test

import (
	&amp;quot;fmt&amp;quot;
	&amp;quot;strings&amp;quot;
	&amp;quot;testing&amp;quot;

	&amp;quot;github.com/gruntwork-io/terratest/modules/random&amp;quot;
	&amp;quot;github.com/gruntwork-io/terratest/modules/terraform&amp;quot;
	&amp;quot;github.com/stretchr/testify/assert&amp;quot;
)

func TestTerraformAwsInstance(t *testing.T) {
	t.Parallel() // run alongside other independent tests

	// Randomize names so parallel runs never collide.
	uniqueID := strings.ToLower(random.UniqueId())

	terraformOptions := &amp;amp;terraform.Options{
		TerraformDir: &amp;quot;../../modules/ec2_instance&amp;quot;,
		Vars: map[string]interface{}{
			&amp;quot;instance_type&amp;quot;: &amp;quot;t2.micro&amp;quot;,
			&amp;quot;name&amp;quot;:          fmt.Sprintf(&amp;quot;terratest-%s&amp;quot;, uniqueID),
			&amp;quot;environment&amp;quot;:   &amp;quot;testing&amp;quot;,
		},
	}

	// `defer` guarantees cleanup even if an assertion fails or panics.
	defer terraform.Destroy(t, terraformOptions)

	terraform.InitAndApply(t, terraformOptions)

	instanceID := terraform.Output(t, terraformOptions, &amp;quot;instance_id&amp;quot;)
	assert.NotEmpty(t, instanceID, &amp;quot;The EC2 instance ID should not be empty&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;defer terraform.Destroy(...)&lt;/code&gt; line is the important one. In Go, &lt;code&gt;defer&lt;/code&gt; runs at the end of the function no matter how it exits, so the resources come down even when the test fails partway through. That is what keeps a failed run from leaving you a bill.&lt;/p&gt;
&lt;h2&gt;Spinning resources up and down safely&lt;/h2&gt;
&lt;p&gt;Testing against a real cloud adds real risks. Two tests that create resources with the same name collide. A crashed runner skips the destroy and leaves you paying for idle infrastructure. A few habits keep it safe.&lt;/p&gt;
&lt;p&gt;&lt;DrawIO
  client:load
  src=&quot;/assets/blog/0108-terraform-testing-terratest-native-tests/aws-test-architecture.drawio&quot;
  title=&quot;Terratest against a dedicated AWS sandbox account&quot;
  caption=&quot;CI authenticates with OIDC to assume a short-lived, scoped role in an isolated test account. Terratest provisions uniquely named resources, asserts via the AWS SDK, then destroys them. A nightly cron sweeps anything a crashed run left behind.&quot;
  height={520}
/&gt;&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Randomize resource names. Never use static strings in integration tests. Feed a unique id (&lt;code&gt;random.UniqueId()&lt;/code&gt;) into your module variables so parallel runs do not collide.&lt;/li&gt;
&lt;li&gt;Use a dedicated test account. Never run automated integration tests in production or staging. Keep a separate AWS account or Azure subscription for CI.&lt;/li&gt;
&lt;li&gt;Run tests in parallel. Cloud provisioning is slow, so use &lt;code&gt;t.Parallel()&lt;/code&gt; on independent tests to cut total pipeline time.&lt;/li&gt;
&lt;li&gt;Add a cleanup safety net. When a runner crashes, &lt;code&gt;defer&lt;/code&gt; never runs. Schedule a nightly cron with a sweeper (for example &lt;code&gt;cloud-nuke&lt;/code&gt;) to delete leftover resources in the test account.&lt;/li&gt;
&lt;/ol&gt;
&lt;/Steps&gt;&lt;h2&gt;Wire it into GitHub Actions&lt;/h2&gt;
&lt;p&gt;Tests only help if they run every time. Put the whole pyramid in CI so it fires on every pull request. For cloud auth, do not store long-lived AWS keys as secrets. Use OpenID Connect so the workflow requests short-lived, temporary credentials at run time.&lt;/p&gt;
&lt;p&gt;&lt;DrawIO
  client:load
  src=&quot;/assets/blog/0108-terraform-testing-terratest-native-tests/ci-pipeline.drawio&quot;
  title=&quot;The CI pipeline&quot;
  caption=&quot;Job 1 runs the fast, free checks (fmt, tflint, mocked unit tests) with no credentials. Only if it passes does Job 2 assume a role via OIDC and run the slower Terratest integration suite.&quot;
  height={440}
/&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Terraform Module CI

on:
  pull_request:
    paths: [&amp;#39;**/*.tf&amp;#39;, &amp;#39;**/*.tftest.hcl&amp;#39;, &amp;#39;**/*_test.go&amp;#39;]

# Required for OIDC: let the workflow mint an ID token.
permissions:
  id-token: write
  contents: read

jobs:
  static-and-unit:
    name: Format, Lint, Unit Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.8.0
      - name: Check formatting
        run: terraform fmt -check -recursive
      - uses: terraform-linters/setup-tflint@v4
        with:
          tflint_version: latest
      - name: Lint
        run: |
          tflint --init
          tflint -f compact
      - name: Unit tests (mocked, no cloud creds)
        run: |
          terraform init -backend=false
          terraform test

  integration:
    name: Terratest Integration
    needs: static-and-unit
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Configure AWS credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-terratest
          aws-region: us-east-1
      - uses: actions/setup-go@v5
        with:
          go-version: &amp;#39;1.22&amp;#39;
      - name: Run Terratest
        working-directory: ./tests/integration
        run: go test -v -timeout 45m
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this in place, no broken syntax, failing logic, or apply-blocking error reaches &lt;code&gt;main&lt;/code&gt;. Reviewers spend their time on architecture instead of hunting for a misspelled variable.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;Accordion client:load title=&quot;Do I still need Terratest now that Terraform has native tests?&quot;&gt;&lt;p&gt;Yes, for different jobs. Native &lt;code&gt;terraform test&lt;/code&gt; is fast unit testing of your logic, especially with mocked providers, and it is free. Terratest provisions real resources and checks them through the cloud SDK, which is the only way to catch apply-time failures like IAM or quota issues. Use native tests for logic and Terratest for the real deployment.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;What is the difference between command = plan and command = apply in a test?&quot;&gt;&lt;p&gt;&lt;code&gt;command = plan&lt;/code&gt; evaluates a plan in memory and asserts against planned values, so nothing is created. &lt;code&gt;command = apply&lt;/code&gt; actually applies the config, which lets you assert on computed outputs that only exist after creation. Plan runs are the default choice for fast unit tests; apply runs cost time and, without mocks, real resources.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Can I run terraform test without cloud credentials?&quot;&gt;&lt;p&gt;Yes. Add a &lt;code&gt;mock_provider&lt;/code&gt; block. It returns the provider schema but generates fake values for computed attributes instead of calling the cloud, so the test runs fully offline. Use &lt;code&gt;override_resource&lt;/code&gt; when a specific computed value needs to be deterministic.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;How do I avoid leftover resources and surprise bills?&quot;&gt;&lt;p&gt;Three things: &lt;code&gt;defer terraform.Destroy(...)&lt;/code&gt; so cleanup runs even on failure, unique resource names so parallel runs do not collide, and a nightly sweeper (like cloud-nuke) in the dedicated test account to catch anything a crashed runner leaves behind.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Why use OIDC instead of AWS access keys in CI?&quot;&gt;&lt;p&gt;Long-lived keys stored as secrets are a standing liability: if they leak, they work until someone rotates them. OIDC establishes a trust relationship so the workflow requests short-lived credentials at run time, scoped to a specific role. Nothing durable to steal.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Where should integration tests run?&quot;&gt;&lt;p&gt;Always in a dedicated, isolated account or subscription, never production or staging. Give the CI role only the permissions the tests need, and keep the blast radius of a bad test inside that sandbox.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.hashicorp.com/terraform/language/tests&quot;&gt;Terraform: Testing Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.hashicorp.com/terraform/language/tests/mocking&quot;&gt;Terraform Tests: Provider Mocking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hashicorp.com/en/blog/terraform-1-7-adds-test-mocking-and-config-driven-remove&quot;&gt;Terraform 1.7 adds test mocking and config-driven remove&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://terratest.gruntwork.io/&quot;&gt;Terratest (Gruntwork)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/terraform-linters/tflint&quot;&gt;TFLint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services&quot;&gt;Configuring OpenID Connect in AWS (GitHub Docs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gruntwork-io/cloud-nuke&quot;&gt;cloud-nuke&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Infrastructure as Code</category><category>DevOps</category><category>Testing</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0108-terraform-testing-terratest-native-tests/hero.png" length="0" type="image/jpeg"/></item><item><title>tRPC: End-to-End Type-Safe APIs in TypeScript Without Codegen</title><link>https://mkabumattar.com/blog/post/trpc-end-to-end-typesafe-apis/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/trpc-end-to-end-typesafe-apis/</guid><description>How tRPC gives full-stack TypeScript teams end-to-end type safety with no code generation: routers, Zod validation, React Query, auth middleware, the v11 features (FormData, SSE, streaming), and when to pick it over REST or GraphQL.</description><pubDate>Mon, 20 Jul 2026 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The line between the frontend and the backend has always been a place where types go to die. In a normal REST setup you define the shape of a request and a response on the server, then you write those same shapes again on the client. Nothing keeps the two copies honest. Someone renames a field in the database, the server response changes, and the client keeps trusting the old shape until a runtime error gives it away in production.&lt;/p&gt;
&lt;p&gt;Code generation and OpenAPI specs try to close that gap, but they cost you a build step and a pile of config to maintain. tRPC takes a different route: if both sides are TypeScript, they can share the same type directly, so the client and server never drift. No generated code, no schema files, no extra pipeline.&lt;/p&gt;
&lt;Notice type=&quot;info&quot;&gt;&lt;p&gt;This post targets full-stack TypeScript teams, usually in a monorepo with Next.js or a Node backend. If your API also serves a Swift app or a Python service, read the last section first, because tRPC is probably the wrong tool for that boundary.&lt;/p&gt;
&lt;/Notice&gt;&lt;h2&gt;What tRPC is and why teams keep reaching for it&lt;/h2&gt;
&lt;p&gt;tRPC (TypeScript Remote Procedure Call) is a small framework for building type-safe APIs. The idea is simple: if the server and the client both run TypeScript, they should share one source of truth for their data contracts instead of maintaining two.&lt;/p&gt;
&lt;p&gt;It is widely used, with tens of thousands of GitHub stars and millions of weekly downloads, and the reason is that it deletes the translation layer most APIs carry. You do not define HTTP endpoints, schema files, and resolvers. You define backend procedures, which are just functions that validate their input and return data. The frontend then imports the &lt;em&gt;type&lt;/em&gt; of those procedures, not the runtime code, and gets autocomplete, strict checking, and an instant compiler error the moment the backend changes.&lt;/p&gt;
&lt;p&gt;In a monorepo that feedback loop is immediate. Rename a field on the server and the client component turns red before you even save the file. That is the whole pitch: the network boundary stops being a place where you guess.&lt;/p&gt;
&lt;h2&gt;How the types actually flow&lt;/h2&gt;
&lt;p&gt;The part that surprises people is that there is no magic and no generated artifact. The server exports a single type built from its router, and the client imports it. The TypeScript compiler does the rest.&lt;/p&gt;
&lt;p&gt;&lt;DrawIO
  client:load
  src=&quot;/assets/blog/0107-trpc-end-to-end-typesafe-apis/architecture.drawio&quot;
  title=&quot;End-to-end type sharing in a monorepo&quot;
  caption=&quot;The server exports `type AppRouter = typeof appRouter`. The client imports that type only (compile time, no codegen) and still talks to the server over normal batched HTTP at runtime.&quot;
  height={520}
/&gt;&lt;/p&gt;
&lt;p&gt;A typical monorepo keeps the router definitions in their own package so server-only code never leaks into the client bundle. The client depends on that package for its &lt;em&gt;types&lt;/em&gt;, not its runtime.&lt;/p&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;my-app/&lt;ul&gt;
&lt;li&gt;apps/&lt;ul&gt;
&lt;li&gt;web/ (Next.js or React frontend)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;packages/&lt;ul&gt;
&lt;li&gt;api/&lt;ul&gt;
&lt;li&gt;src/&lt;ul&gt;
&lt;li&gt;init.ts (tRPC instance + context)&lt;/li&gt;
&lt;li&gt;routers/&lt;ul&gt;
&lt;li&gt;_app.ts (root router, exports AppRouter type)&lt;/li&gt;
&lt;li&gt;user.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;server.ts (HTTP adapter)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;h2&gt;How tRPC differs from REST and GraphQL&lt;/h2&gt;
&lt;p&gt;REST, GraphQL, and tRPC each treat type safety differently, and the differences explain when each one fits.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Feature&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;tRPC&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;GraphQL&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;REST&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Protocol&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;RPC over HTTP&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Query language over HTTP&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;HTTP verbs and resources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Schema format&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;TypeScript (source of truth)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;SDL (&lt;code&gt;.graphql&lt;/code&gt; files)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;OpenAPI or none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Type safety&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;End-to-end, automatic&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Generated via codegen&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Generated or manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Client coupling&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Tight (shares types)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Loose (schema contract)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Loose (HTTP contract)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Multi-client support&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;TypeScript only&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Excellent&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;REST usually gets its types from a spec. You produce an OpenAPI document from the server and run something like &lt;code&gt;openapi-typescript&lt;/code&gt; to generate client types. It works, but the safety lives or dies by that build step, and a skipped or broken generation quietly leaves you with a loosely typed boundary again.&lt;/p&gt;
&lt;p&gt;GraphQL leans on a strongly typed schema (SDL) and a codegen step (&lt;code&gt;graphql-codegen&lt;/code&gt;) to turn that schema into client types. The safety is real, but so is the boilerplate: schema, resolvers, and queries are all written separately.&lt;/p&gt;
&lt;p&gt;tRPC skips the schema and the codegen entirely. The server exports a TypeScript type, the client imports it, and the compiler infers everything. There is no step to keep the two sides in sync because they are literally reading the same type.&lt;/p&gt;
&lt;h2&gt;Setting up a tRPC server&lt;/h2&gt;
&lt;p&gt;A server needs three things: a context, an initialized tRPC instance, and an HTTP adapter. tRPC ships official adapters for Express, Fastify, the Fetch API (Next.js App Router, edge runtimes), and the plain Node HTTP server.&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Create the context factory. It runs per request and is where you read the auth token and attach shared resources like a database client.&lt;/li&gt;
&lt;li&gt;Initialize tRPC with that context type, and export the reusable &lt;code&gt;router&lt;/code&gt; and &lt;code&gt;publicProcedure&lt;/code&gt; builders.&lt;/li&gt;
&lt;li&gt;Mount the root router on an HTTP adapter for your framework.&lt;/li&gt;
&lt;/ol&gt;
&lt;/Steps&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {db} from &amp;#39;./db&amp;#39;;
import {initTRPC, TRPCError} from &amp;#39;@trpc/server&amp;#39;;
import type {CreateExpressContextOptions} from &amp;#39;@trpc/server/adapters/express&amp;#39;;

// Runs on every request. Whatever you return here is the `ctx` in procedures.
export function createContext({req}: CreateExpressContextOptions) {
  const token = req.headers.authorization?.replace(&amp;#39;Bearer &amp;#39;, &amp;#39;&amp;#39;) ?? null;
  return {token, db};
}

export type Context = Awaited&amp;lt;ReturnType&amp;lt;typeof createContext&amp;gt;&amp;gt;;

const t = initTRPC.context&amp;lt;Context&amp;gt;().create();

export const router = t.router;
export const publicProcedure = t.procedure;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The adapter is the only part that changes between frameworks. Everything above stays identical.&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Express&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {createContext} from &amp;#39;./init&amp;#39;;
import {appRouter} from &amp;#39;./routers/_app&amp;#39;;
import {createExpressMiddleware} from &amp;#39;@trpc/server/adapters/express&amp;#39;;
import express from &amp;#39;express&amp;#39;;

const app = express();

app.use(&amp;#39;/trpc&amp;#39;, createExpressMiddleware({router: appRouter, createContext}));

app.listen(4000, () =&amp;gt; console.log(&amp;#39;tRPC on http://localhost:4000/trpc&amp;#39;));
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Next.js (App Router)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {createContext} from &amp;#39;@repo/api/init&amp;#39;;
import {appRouter} from &amp;#39;@repo/api/routers/_app&amp;#39;;
import {fetchRequestHandler} from &amp;#39;@trpc/server/adapters/fetch&amp;#39;;

const handler = (req: Request) =&amp;gt;
  fetchRequestHandler({
    endpoint: &amp;#39;/api/trpc&amp;#39;,
    req,
    router: appRouter,
    createContext,
  });

export {handler as GET, handler as POST};
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;h2&gt;Routers, procedures, and input validation with Zod&lt;/h2&gt;
&lt;p&gt;A procedure is one endpoint. It is either a &lt;code&gt;query&lt;/code&gt; (reads) or a &lt;code&gt;mutation&lt;/code&gt; (writes), and procedures are grouped into routers. Input validation is not optional here, and tRPC integrates natively with Zod, which is the community default because its inference lines up perfectly with TypeScript.&lt;/p&gt;
&lt;p&gt;When you pass a Zod schema to &lt;code&gt;.input()&lt;/code&gt;, tRPC uses it twice. At runtime the server parses the request against the schema and throws if the data is malformed. At compile time it infers the type from the same schema and enforces it on the client, so the client cannot even send the wrong shape.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {router, publicProcedure} from &amp;#39;../init&amp;#39;;
import {z} from &amp;#39;zod&amp;#39;;

export const userRouter = router({
  // Query: fetching data
  getById: publicProcedure
    .input(z.object({id: z.string().uuid()}))
    .query(async ({input, ctx}) =&amp;gt; {
      // `input.id` is a validated string by the time we get here.
      return ctx.db.user.findUnique(input.id);
    }),

  // Mutation: changing data
  create: publicProcedure
    .input(z.object({email: z.string().email(), name: z.string().min(2)}))
    .mutation(async ({input, ctx}) =&amp;gt; {
      return ctx.db.user.create(input);
    }),
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Individual routers merge into one root router, and that root router is the only thing the frontend needs a type for.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {router} from &amp;#39;../init&amp;#39;;
import {userRouter} from &amp;#39;./user&amp;#39;;

export const appRouter = router({
  user: userRouter,
});

// The single type the frontend imports.
export type AppRouter = typeof appRouter;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The request lifecycle&lt;/h2&gt;
&lt;p&gt;It helps to see what a single call actually does on the way through. The client batches the call, the adapter builds a context, middleware runs, Zod validates, and only then does your resolver see the data.&lt;/p&gt;
&lt;p&gt;&lt;DrawIO
  client:load
  src=&quot;/assets/blog/0107-trpc-end-to-end-typesafe-apis/request-workflow.drawio&quot;
  title=&quot;A tRPC request from click to typed response&quot;
  caption=&quot;Auth and validation happen before your resolver runs. A failed check short-circuits with a typed TRPCError (401 or 400) instead of reaching your business logic.&quot;
  height={720}
/&gt;&lt;/p&gt;
&lt;h2&gt;Integrating with React Query on the frontend&lt;/h2&gt;
&lt;p&gt;tRPC has a first-class integration with TanStack React Query. Version 11 changed how it works. The old approach wrapped React Query in tRPC-specific hooks like &lt;code&gt;trpc.useQuery&lt;/code&gt;. The new integration, in &lt;code&gt;@trpc/tanstack-react-query&lt;/code&gt;, is query-native: it hands you the &lt;code&gt;queryOptions&lt;/code&gt; and &lt;code&gt;mutationOptions&lt;/code&gt; that TanStack Query already understands, so you call the standard &lt;code&gt;useQuery&lt;/code&gt; and &lt;code&gt;useMutation&lt;/code&gt; yourself. Less to learn, and it plays nicely with the React Compiler.&lt;/p&gt;
&lt;p&gt;You set up a proxy once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import type {AppRouter} from &amp;#39;@repo/api/routers/_app&amp;#39;;
import {QueryClient} from &amp;#39;@tanstack/react-query&amp;#39;;
import {createTRPCClient, httpBatchLink} from &amp;#39;@trpc/client&amp;#39;;
import {createTRPCOptionsProxy} from &amp;#39;@trpc/tanstack-react-query&amp;#39;;

export const queryClient = new QueryClient();

const trpcClient = createTRPCClient&amp;lt;AppRouter&amp;gt;({
  links: [httpBatchLink({url: &amp;#39;http://localhost:4000/trpc&amp;#39;})],
});

// Strongly-typed factory for query keys, query options, and mutation options.
export const trpc = createTRPCOptionsProxy&amp;lt;AppRouter&amp;gt;({
  client: trpcClient,
  queryClient,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you use plain TanStack Query hooks in components. The proxy supplies the typed keys, the URL, and the fetching logic.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#39;use client&amp;#39;;
import {trpc, queryClient} from &amp;#39;../trpc&amp;#39;;
import {useQuery, useMutation} from &amp;#39;@tanstack/react-query&amp;#39;;

export function UserProfile({userId}: {userId: string}) {
  const {data, isLoading, error} = useQuery(
    trpc.user.getById.queryOptions({id: userId}),
  );

  const {mutate, isPending} = useMutation(
    trpc.user.create.mutationOptions({
      onSuccess: () =&amp;gt;
        queryClient.invalidateQueries({
          queryKey: trpc.user.getById.queryKey(),
        }),
    }),
  );

  if (isLoading) return &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;;
  if (error) return &amp;lt;div&amp;gt;Error fetching user.&amp;lt;/div&amp;gt;;

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;{data?.name}&amp;lt;/h1&amp;gt;
      &amp;lt;button
        disabled={isPending}
        onClick={() =&amp;gt; mutate({email: &amp;#39;test@example.com&amp;#39;, name: &amp;#39;Alice&amp;#39;})}
      &amp;gt;
        {isPending ? &amp;#39;Saving...&amp;#39; : &amp;#39;Create User&amp;#39;}
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Authentication and middleware&lt;/h2&gt;
&lt;p&gt;Middleware intercepts a request before it reaches your resolver, which makes it the right home for logging, timing, and authorization. The pattern for auth is to check the context and then extend it with &lt;code&gt;opts.next()&lt;/code&gt;, so downstream procedures receive a guaranteed, non-null user.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {verifyToken} from &amp;#39;./auth&amp;#39;;
import {t} from &amp;#39;./init&amp;#39;;
import {TRPCError} from &amp;#39;@trpc/server&amp;#39;;

const isAuthed = t.middleware(async ({ctx, next}) =&amp;gt; {
  if (!ctx.token) {
    throw new TRPCError({code: &amp;#39;UNAUTHORIZED&amp;#39;, message: &amp;#39;Missing token&amp;#39;});
  }

  const user = await verifyToken(ctx.token);
  if (!user) throw new TRPCError({code: &amp;#39;UNAUTHORIZED&amp;#39;});

  // Extend the context. From here down, `ctx.user` is guaranteed to exist.
  return next({ctx: {user}});
});

export const protectedProcedure = t.procedure.use(isAuthed);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the middleware narrows the type, any procedure built on &lt;code&gt;protectedProcedure&lt;/code&gt; gets a non-nullable &lt;code&gt;ctx.user&lt;/code&gt; with no extra null checks.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {router, protectedProcedure} from &amp;#39;../init&amp;#39;;

export const adminRouter = router({
  getDashboardStats: protectedProcedure.query(({ctx}) =&amp;gt; {
    // TypeScript knows `ctx.user` is defined here.
    console.log(`Stats for admin ${ctx.user.id}`);
    return {activeUsers: 100, revenue: 5000};
  }),
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What is new in v11&lt;/h2&gt;
&lt;p&gt;tRPC v11 (March 2025) pushed past plain request/response, and these are the additions most teams will actually use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FormData and file uploads.&lt;/strong&gt; Procedures can now accept non-JSON content, including &lt;code&gt;FormData&lt;/code&gt; and binary types like &lt;code&gt;Blob&lt;/code&gt;, &lt;code&gt;File&lt;/code&gt;, and &lt;code&gt;Uint8Array&lt;/code&gt;. That means real file uploads without a separate REST endpoint.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {router, publicProcedure} from &amp;#39;../init&amp;#39;;
import {TRPCError} from &amp;#39;@trpc/server&amp;#39;;
import {z} from &amp;#39;zod&amp;#39;;

export const uploadRouter = router({
  avatar: publicProcedure
    .input(z.instanceof(FormData))
    .mutation(async ({input}) =&amp;gt; {
      const file = input.get(&amp;#39;file&amp;#39;);
      if (!(file instanceof File)) {
        throw new TRPCError({code: &amp;#39;BAD_REQUEST&amp;#39;, message: &amp;#39;No file&amp;#39;});
      }
      // stream `file` to storage here...
      return {name: file.name, size: file.size};
    }),
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Subscriptions over Server-Sent Events.&lt;/strong&gt; Real-time updates no longer force you onto WebSockets. Subscriptions are written as async generators, so you &lt;code&gt;yield&lt;/code&gt; values over time and clean up naturally when the client disconnects.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {router, publicProcedure} from &amp;#39;../init&amp;#39;;
import {z} from &amp;#39;zod&amp;#39;;

export const messageRouter = router({
  onMessage: publicProcedure
    .input(z.object({roomId: z.string()}))
    .subscription(async function* ({input, ctx, signal}) {
      // `ctx.bus` is any async iterable event source.
      for await (const msg of ctx.bus.subscribe(input.roomId, {signal})) {
        yield msg; // pushed to the client over SSE
      }
    }),
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Streaming queries and mutations.&lt;/strong&gt; With &lt;code&gt;httpBatchStreamLink&lt;/code&gt;, a resolver can return a generator and stream results over plain HTTP, no WebSocket required. Pair it with &lt;code&gt;httpSubscriptionLink&lt;/code&gt; for the SSE subscriptions above.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {
  createTRPCClient,
  httpBatchStreamLink,
  httpSubscriptionLink,
  splitLink,
} from &amp;#39;@trpc/client&amp;#39;;

const trpcClient = createTRPCClient&amp;lt;AppRouter&amp;gt;({
  links: [
    splitLink({
      condition: (op) =&amp;gt; op.type === &amp;#39;subscription&amp;#39;,
      true: httpSubscriptionLink({url: &amp;#39;/trpc&amp;#39;}),
      false: httpBatchStreamLink({url: &amp;#39;/trpc&amp;#39;}),
    }),
  ],
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Subscriptions also gained output validators in v11, so the values you stream are type-checked the same way inputs are.&lt;/p&gt;
&lt;h2&gt;When to choose tRPC, GraphQL, or REST&lt;/h2&gt;
&lt;p&gt;tRPC is not a universal answer. The call comes down to who consumes the API and what language they speak.&lt;/p&gt;
&lt;p&gt;Reach for tRPC when you own both ends and they are both TypeScript, usually in a monorepo. Internal dashboards, SaaS products on Next.js or React, and anything where developer speed matters most are where it shines. Dropping schema files and codegen is a real velocity win for a TypeScript-only team.&lt;/p&gt;
&lt;p&gt;Stay on REST for public APIs. If your backend has to serve a Swift app, Python microservices, or partner integrations, REST gives you the HTTP semantics, caching, and tooling everyone already supports. Adapters like &lt;code&gt;trpc-openapi&lt;/code&gt; can expose REST endpoints from tRPC procedures, but treating REST as an afterthought rarely ends well for heavy public use.&lt;/p&gt;
&lt;p&gt;Pick GraphQL for federated microservices or complex clients that need fine-grained control over payloads to avoid over-fetching. Its schema contracts let independent teams work across a big graph and aggregate many systems into one API, which is exactly the problem tRPC does not try to solve.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;Accordion client:load title=&quot;Does tRPC replace REST or GraphQL?&quot;&gt;&lt;p&gt;No. It is a better fit for one specific case: a full-stack TypeScript codebase where you control the client and the server. Public APIs and non-TypeScript consumers are still REST or GraphQL territory.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Is there really no code generation?&quot;&gt;&lt;p&gt;Correct. The server exports &lt;code&gt;type AppRouter = typeof appRouter&lt;/code&gt; and the client imports that type. TypeScript infers everything, so there is no schema file and no generation step to run or keep in sync.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Why is Zod the default validator?&quot;&gt;&lt;p&gt;tRPC works with Zod, Yup, Valibot, and others, but Zod is standard because its inference maps cleanly onto TypeScript. One schema gives you runtime validation and the compile-time input type at once.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Do I have to use a monorepo?&quot;&gt;&lt;p&gt;Not strictly, but it is the smoothest setup because the client imports the server&amp;#39;s type directly. You can also publish the API package privately and consume its types from a separate repo, at the cost of a versioning step.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Can tRPC do real-time and file uploads now?&quot;&gt;&lt;p&gt;Yes, as of v11. Subscriptions run over Server-Sent Events using async generators, and procedures accept &lt;code&gt;FormData&lt;/code&gt; and binary types for uploads. You no longer need a side channel for either.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;How do errors reach the client?&quot;&gt;&lt;p&gt;You throw a &lt;code&gt;TRPCError&lt;/code&gt; with a code like &lt;code&gt;UNAUTHORIZED&lt;/code&gt; or &lt;code&gt;BAD_REQUEST&lt;/code&gt;. tRPC maps it to the right HTTP status and delivers a typed error to the client, where React Query surfaces it as the &lt;code&gt;error&lt;/code&gt; on the hook.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://trpc.io/blog/announcing-trpc-v11&quot;&gt;Announcing tRPC v11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trpc.io/docs/migrate-from-v10-to-v11&quot;&gt;Migrate from v10 to v11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trpc.io/blog/introducing-tanstack-react-query-client&quot;&gt;Introducing the new TanStack React Query integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trpc.io/docs/client/tanstack-react-query/usage&quot;&gt;TanStack React Query usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trpc.io/docs/server/adapters/express&quot;&gt;tRPC Express adapter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trpc.io/docs/server/adapters/fetch&quot;&gt;tRPC Fetch adapter (Next.js / edge)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trpc.io/docs/server/middlewares&quot;&gt;Middlewares and context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trpc.io/docs/server/subscriptions&quot;&gt;Subscriptions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zod.dev/&quot;&gt;Zod&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Web Development</category><category>Backend Engineering</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0107-trpc-end-to-end-typesafe-apis/hero.png" length="0" type="image/jpeg"/></item><item><title>FinOps in Practice: How to Build a Cloud Cost Accountability Culture on AWS</title><link>https://mkabumattar.com/blog/post/finops-cloud-cost-accountability-aws/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/finops-cloud-cost-accountability-aws/</guid><description>How to run FinOps as a real practice on AWS: a lean tagging taxonomy enforced with Terraform and Organizations, automated budgets and anomaly detection, showback vs chargeback, and matching Savings Plans to your architecture roadmap.</description><pubDate>Tue, 14 Jul 2026 13:48:02 GMT</pubDate><content:encoded>&lt;p&gt;Cloud computing changed how businesses pay for technology. Instead of a slow procurement cycle to buy physical servers, a single engineer can spin up thousands of dollars of infrastructure in minutes. That speed is the point. It is also how spending fragments and hides until it outpaces revenue. Most enterprises report going over their cloud budgets, and a large share of every cloud bill goes to resources that sit idle or run far bigger than they need to.&lt;/p&gt;
&lt;h2&gt;What is FinOps and why does it go beyond cost dashboards?&lt;/h2&gt;
&lt;p&gt;FinOps, short for Financial Operations, is an operating model that brings finance, engineering, and business leadership into the same conversation about cloud spend. The goal is not to cut costs. It is to get the most business value from every dollar of cloud investment and keep innovation financially sustainable.&lt;/p&gt;
&lt;p&gt;Plenty of teams think they are doing FinOps because they opened a dashboard in AWS Cost Explorer. Visibility alone does not change behavior. Hand an engineering team an aggregated monthly bill and you have given them a number, not a decision. A mature practice turns that number into unit economics: cost per customer transaction, cost per active user. Now infrastructure spend reads as a variable tied to business value instead of vague overhead.&lt;/p&gt;
&lt;p&gt;The work usually moves through three phases, and you cycle back through them: Inform, Optimize, Operate. Make spend visible, improve efficiency, then bake cost awareness into daily engineering rituals.&lt;/p&gt;
&lt;h2&gt;How do you implement tagging strategies that drive cost attribution?&lt;/h2&gt;
&lt;p&gt;Accurate cost attribution is the backbone of cloud financial management. Without consistent metadata on your resources, reports turn into noise. You cannot map costs to a team, product, or environment when nothing is labeled.&lt;/p&gt;
&lt;p&gt;A good tagging strategy balances governance against developer experience. Mandate twenty tags on day one and teams will route around every rule. Start with a small, focused set of mandatory tags instead.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Tag Key&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Example Values&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;CostCenter&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;Engineering&lt;/code&gt;, &lt;code&gt;Marketing&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Maps infrastructure to internal accounting for chargeback.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;Environment&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;Dev&lt;/code&gt;, &lt;code&gt;Staging&lt;/code&gt;, &lt;code&gt;Prod&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Drives per-environment budgets and automated shutdown of non-prod resources.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;Application&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;PaymentAPI&lt;/code&gt;, &lt;code&gt;UserPortal&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Enables application-level cost analysis and unit economics.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;Owner&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;platform-team@company.com&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Names the team accountable for the resource.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;ManagedBy&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;Terraform&lt;/code&gt;, &lt;code&gt;CloudFormation&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Records how the resource was provisioned, flagging manual console changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Manual tagging fails at scale. Enforce tags programmatically with AWS Organizations, Service Control Policies, and Infrastructure as Code.&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define Organizational Tag Policies.&lt;/strong&gt; AWS Organizations Tag Policies set the acceptable keys and values across your whole footprint. You can require that any &lt;code&gt;Environment&lt;/code&gt; tag uses exactly &lt;code&gt;Dev&lt;/code&gt;, &lt;code&gt;Staging&lt;/code&gt;, or &lt;code&gt;Prod&lt;/code&gt;, which stops messy variants like &lt;code&gt;production&lt;/code&gt; or &lt;code&gt;PROD&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add Service Control Policies (SCPs).&lt;/strong&gt; SCPs block non-compliant resources before they exist. An SCP can deny &lt;code&gt;ec2:RunInstances&lt;/code&gt; when a required tag is missing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Embed tags in Infrastructure as Code.&lt;/strong&gt; Terraform applies default tags to every resource in a provider configuration, giving you a consistent baseline.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validate in the pipeline.&lt;/strong&gt; Check Terraform plans against your policies before deployment, so compliance issues surface in CI rather than in the bill.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/Steps&gt;&lt;p&gt;The &lt;code&gt;default_tags&lt;/code&gt; block on the AWS provider is the cheapest win here. Every resource created through that provider inherits the tags automatically.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;# main.tf
provider &amp;quot;aws&amp;quot; {
  region = &amp;quot;us-east-1&amp;quot;

  default_tags {
    tags = {
      Environment = &amp;quot;Prod&amp;quot;
      CostCenter  = &amp;quot;1001&amp;quot;
      ManagedBy   = &amp;quot;Terraform&amp;quot;
    }
  }
}

# This EC2 instance inherits the provider&amp;#39;s default_tags automatically.
resource &amp;quot;aws_instance&amp;quot; &amp;quot;app_server&amp;quot; {
  ami           = &amp;quot;ami-0c55b159cbfafe1f0&amp;quot;
  instance_type = &amp;quot;t3.medium&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;Notice type=&quot;tip&quot;&gt;
  Tag Policy enforcement lives in AWS Organizations, not in the Terraform
  provider. Pair `default_tags` for the baseline with an Organizations Tag
  Policy (and an SCP) so drift gets caught centrally. In multi-team setups, a
  platform team usually ships a shared Terraform tagging module so the taxonomy
  stays identical everywhere.
&lt;/Notice&gt;&lt;h2&gt;How do you set up AWS Cost Explorer, Budgets, and anomaly detection?&lt;/h2&gt;
&lt;p&gt;Even with perfect tagging, costs spike. A misconfigured auto-scaling group, an accidental deploy to an expensive instance type, or a runaway serverless loop can run up a large bill overnight. You need automated guardrails to catch these before the invoice does.&lt;/p&gt;
&lt;p&gt;AWS Cost Anomaly Detection uses machine learning to learn your spending baseline. When something unusual shows up, like a sudden jump in data transfer, it alerts you within hours instead of at month end. Monitors are either &lt;code&gt;DIMENSIONAL&lt;/code&gt; (scoped to services or linked accounts) or &lt;code&gt;CUSTOM&lt;/code&gt; (scoped to cost allocation tags or categories). Build them in Terraform and every new project ships with a tripwire already armed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;# Service-level anomaly monitor
resource &amp;quot;aws_ce_anomaly_monitor&amp;quot; &amp;quot;service_monitor&amp;quot; {
  name              = &amp;quot;Core-Services-Anomaly-Monitor&amp;quot;
  monitor_type      = &amp;quot;DIMENSIONAL&amp;quot;
  monitor_dimension = &amp;quot;SERVICE&amp;quot;
}

# Alert the FinOps team when an anomaly&amp;#39;s impact exceeds $100
resource &amp;quot;aws_ce_anomaly_subscription&amp;quot; &amp;quot;finops_alerts&amp;quot; {
  name             = &amp;quot;FinOps-Critical-Alerts&amp;quot;
  frequency        = &amp;quot;DAILY&amp;quot;
  monitor_arn_list = [aws_ce_anomaly_monitor.service_monitor.arn]

  subscriber {
    type    = &amp;quot;EMAIL&amp;quot;
    address = &amp;quot;finops-alerts@organization.com&amp;quot;
  }

  threshold_expression {
    dimension {
      key           = &amp;quot;ANOMALY_TOTAL_IMPACT_ABSOLUTE&amp;quot;
      values        = [&amp;quot;100&amp;quot;]
      match_options = [&amp;quot;GREATER_THAN_OR_EQUAL&amp;quot;]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anomaly Detection catches the unexpected. AWS Budgets tracks planned spend against a fixed limit and alerts you when forecasted costs cross your monthly allocation. You can create one from the CLI:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;aws budgets create-budget \
  --account-id 111122223333 \
  --budget &amp;#39;{
    &amp;quot;BudgetName&amp;quot;: &amp;quot;MonthlyBudget&amp;quot;,
    &amp;quot;BudgetLimit&amp;quot;: { &amp;quot;Amount&amp;quot;: &amp;quot;1000&amp;quot;, &amp;quot;Unit&amp;quot;: &amp;quot;USD&amp;quot; },
    &amp;quot;TimeUnit&amp;quot;: &amp;quot;MONTHLY&amp;quot;,
    &amp;quot;BudgetType&amp;quot;: &amp;quot;COST&amp;quot;
  }&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Chargeback vs. showback: how do you choose?&lt;/h2&gt;
&lt;p&gt;Visibility is only the first phase. Next you have to fold those numbers into how the organization actually behaves, and that means picking a showback or chargeback model.&lt;/p&gt;
&lt;p&gt;Showback is a reporting mechanism. You show each engineering and product team the cost their workloads generate, but central IT or finance still pays the unified bill. It is the safer place to start. It builds financial awareness and drives optimization without starting turf wars over internal billing.&lt;/p&gt;
&lt;p&gt;Chargeback goes further and cross-charges cloud spend straight to each business unit&amp;#39;s profit and loss. Accountability gets real. Over-provision an expensive database fleet and your own budget takes the hit.&lt;/p&gt;
&lt;Notice type=&quot;warning&quot;&gt;
  Chargeback needs very high tagging compliance, and 100% is rarely realistic
  because of shared resources like transit gateways or multi-tenant Kubernetes
  clusters. AWS Cost Categories helps: it is a rules engine at the billing level
  that maps spend to your org structure by logic, so it can absorb minor tagging
  gaps and keep chargebacks reliable.
&lt;/Notice&gt;&lt;h2&gt;How do you optimize with Reserved Instances, Savings Plans, and Spot strategies?&lt;/h2&gt;
&lt;p&gt;Once visibility and accountability are running, you tune unit economics with commitment-based discounts. Choosing the right one is a trade between how deep the discount goes and how much flexibility your architecture keeps.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Instrument&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Max Discount&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Flexibility&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Best fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Compute Savings Plans&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;~66%&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Very high. Applies across any region, instance family, OS, Fargate, and Lambda.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Dynamic workloads, serverless, and architectures still being modernized (for example, moving to Graviton).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;EC2 Instance Savings Plans&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;~72%&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Moderate. Locked to an instance family and region, flexible on size and OS.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Stable EC2 workloads that will not change architecture or region during the term.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Standard Reserved Instances&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;~75%&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Rigid. Locked to instance type, region, OS, and tenancy. Zonal RIs also reserve capacity.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Legacy, ultra-stable environments and mission-critical databases needing capacity guarantees.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Database Savings Plans&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;~35%&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;High. Applies across eligible engines (Aurora, RDS, ElastiCache, OpenSearch, and more), regions, and sizes.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Multi-engine database estates that change often. 1-year, No Upfront terms.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The common mistake is chasing the biggest headline discount for a workload you are about to modernize. Buy a 3-year EC2 Instance Savings Plan for the &lt;code&gt;m5&lt;/code&gt; family, then migrate the app to &lt;code&gt;m7g&lt;/code&gt; Graviton for better price-performance, and the &lt;code&gt;m5&lt;/code&gt; commitment is stranded. You pay for it anyway. The small premium on a Compute Savings Plan is cheap insurance against exactly that.&lt;/p&gt;
&lt;p&gt;Database Savings Plans extend the flexible, spend-based model to the data tier. Covering engines from Aurora and RDS to OpenSearch, they reach roughly 35% on a 1-year, No Upfront basis, which suits teams whose database mix keeps shifting.&lt;/p&gt;
&lt;h3&gt;Keeping discounts fair with RISP group sharing&lt;/h3&gt;
&lt;p&gt;In a multi-account AWS Organization, Consolidated Billing aggregates usage and automatically applies unused Savings Plans or RIs from one account to eligible usage in another. That maximizes total savings, but it breaks strict chargeback: a business unit that funded a 3-year commitment can watch its discount land on another department&amp;#39;s workloads.&lt;/p&gt;
&lt;p&gt;RISP (Reserved Instances and Savings Plans) group sharing, built on Cost Categories, fixes that with two modes:&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prioritized group sharing.&lt;/strong&gt; Commitments apply first to the purchasing account, then to its defined group (say, one business unit), and only spill over to the rest of the org if capacity is left.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Restricted group sharing.&lt;/strong&gt; Commitments stay isolated inside the defined group. Unused capacity does not spill over, which keeps budgets fully segregated.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/Steps&gt;&lt;p&gt;Set those boundaries and FinOps teams can keep chargeback accurate while the departments that fund a commitment actually benefit from it.&lt;/p&gt;
&lt;h2&gt;How do you make engineering teams responsible for their cloud spend?&lt;/h2&gt;
&lt;p&gt;Tooling is the foundation. Adoption is cultural. Keep cost management locked inside finance and engineers will treat it as someone else&amp;#39;s constraint bolted on from outside. Accountability comes from folding cost awareness into the engineering lifecycle itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shift cost left.&lt;/strong&gt; Let engineers see the financial impact of a design before it ships. Wire cost estimation into pull requests so a change to a Terraform template shows its effect on the monthly bill right there in review. Treat cost as a first-class design constraint next to security and performance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Define service ownership.&lt;/strong&gt; Every significant resource or microservice needs a named owner, accountable for its cost efficiency as well as its uptime.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Make the rituals real.&lt;/strong&gt; Cost reviews should not be an annual budgeting event. Put cost metrics into sprint reviews and operational readiness checks. Track things like tag coverage and how long it takes to remediate an anomaly.&lt;/p&gt;
&lt;p&gt;Make spend visible, attribute it accurately with disciplined tagging, automate the guardrails, and align your discount strategy with your architecture roadmap. Do that and the cloud bill stops being an unpredictable liability and becomes a managed, strategic investment. The cloud gives you the flexibility to move fast. FinOps gives you the discipline to keep doing it sustainably.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;Accordion client:load title=&quot;What is the difference between FinOps and just using AWS Cost Explorer?&quot;&gt;&lt;p&gt;Cost Explorer gives you visibility, which is the starting line, not the finish. FinOps is the operating model on top of it: turning the aggregated bill into unit economics, assigning ownership, automating guardrails, and building rituals so teams change what they provision. A dashboard reports the number. FinOps changes the behavior behind it.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Should I start with showback or chargeback?&quot;&gt;&lt;p&gt;Start with showback. It shows each team the cost of its own workloads while finance still pays the unified bill, so you build awareness without triggering fights over internal billing. Move to chargeback only once your tagging is trustworthy and shared-cost allocation (via AWS Cost Categories) is in place.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Why pick a Compute Savings Plan over a cheaper Reserved Instance?&quot;&gt;&lt;p&gt;Reserved Instances and EC2 Instance Savings Plans offer deeper discounts but lock you to an instance family and region. If you later migrate, for example to Graviton, that commitment is stranded and you keep paying for it. A Compute Savings Plan gives up a few points of discount for flexibility across families, regions, Fargate, and Lambda. For any workload you plan to modernize, that flexibility is cheap insurance.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;How do I enforce tagging without slowing engineers down?&quot;&gt;&lt;p&gt;Keep the mandatory set small, around five tags, and enforce it in code rather than by policy memo. Use the provider&amp;#39;s &lt;code&gt;default_tags&lt;/code&gt; for a baseline, AWS Organizations Tag Policies for allowed keys and values, and an SCP to block non-compliant resources. Validate Terraform plans in CI so problems surface in review, not in production or on the invoice.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;What is RISP group sharing and when do I need it?&quot;&gt;&lt;p&gt;RISP group sharing controls how Reserved Instances and Savings Plans are shared across a multi-account AWS Organization. By default, Consolidated Billing spreads unused commitments anywhere in the org, which breaks strict chargeback. Prioritized sharing keeps commitments with the purchasing account and its group first; restricted sharing isolates them entirely. Use it when a business unit funds its own commitments and needs to see the benefit land on its own budget.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS Organizations Tag Policies and Service Control Policies&lt;/li&gt;
&lt;li&gt;Terraform AWS provider: &lt;code&gt;default_tags&lt;/code&gt; and cost-management resources&lt;/li&gt;
&lt;li&gt;AWS Cost Anomaly Detection with Terraform (&lt;code&gt;aws_ce_anomaly_monitor&lt;/code&gt;, &lt;code&gt;aws_ce_anomaly_subscription&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Managing costs with AWS Budgets from the AWS CLI&lt;/li&gt;
&lt;li&gt;Savings Plans vs. Reserved Instances decision guide&lt;/li&gt;
&lt;li&gt;AWS Database Savings Plans announcement&lt;/li&gt;
&lt;li&gt;Cross-account sharing and Consolidated Billing in AWS&lt;/li&gt;
&lt;li&gt;FinOps Foundation: framework and cultural practices&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Cloud Computing</category><category>DevOps</category><category>Management</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0106-finops-cloud-cost-accountability-aws/hero.png" length="0" type="image/jpeg"/></item><item><title>QuenchWorks: A Zero-CVE, Built-From-Source Replacement for the Bitnami Catalog</title><link>https://mkabumattar.com/blog/post/quenchworks-zero-cve-bitnami-alternative-wolfi/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/quenchworks-zero-cve-bitnami-alternative-wolfi/</guid><description>When Broadcom moved the free Bitnami catalog to a legacy tier, thousands of teams lost their supply of maintained, hardened container images overnight. QuenchWorks is my answer: over 150 container images and 120 Helm charts, rebuilt from source on Wolfi, scanned to zero fixable CVEs, cosign-signed, and pinned by digest. Here is why I built it and how it actually works.</description><pubDate>Wed, 08 Jul 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you run anything on Kubernetes, there&amp;#39;s a good chance you were pulling Bitnami images without even thinking about it. &lt;code&gt;bitnami/postgresql&lt;/code&gt;, &lt;code&gt;bitnami/redis&lt;/code&gt;, &lt;code&gt;bitnami/nginx&lt;/code&gt;, the whole Helm charts library sitting on top of them. For years it was just there, free, maintained, and reasonably well hardened. You built on it and moved on.&lt;/p&gt;
&lt;p&gt;Then in 2025 that quietly stopped being true.&lt;/p&gt;
&lt;p&gt;Broadcom, which now owns VMware and Bitnami, announced they were moving the free Bitnami catalog on Docker Hub to a &lt;code&gt;bitnamilegacy&lt;/code&gt; tier and pushing the actively maintained, security-hardened images into a paid product called Bitnami Secure Images. In plain terms: the free images you were pulling would keep existing, but they would stop getting patched. If you wanted the hardened, CVE-managed versions going forward, you needed a subscription.&lt;/p&gt;
&lt;p&gt;For a lot of teams that&amp;#39;s a genuine problem, not just an annoyance. You suddenly have production workloads sitting on a base of container images that nobody upstream is patching anymore. So I did the thing every engineer eventually does when a tool they depend on disappears. I rebuilt it.&lt;/p&gt;
&lt;p&gt;This is the story of &lt;strong&gt;QuenchWorks&lt;/strong&gt;, and how it actually works under the hood.&lt;/p&gt;
&lt;h2&gt;What actually happened to Bitnami?&lt;/h2&gt;
&lt;p&gt;Let me be precise here, because &amp;quot;Bitnami is dead&amp;quot; is not quite right and I don&amp;#39;t want to spread the panicky version.&lt;/p&gt;
&lt;p&gt;The free catalog didn&amp;#39;t vanish. What changed is the maintenance story. The images that used to receive regular security updates for free got moved behind Bitnami Secure Images, and the free tier became a frozen legacy snapshot. A frozen container image is fine on day one and a slowly growing liability on day ninety, because CVEs get discovered in software you already shipped. An image that isn&amp;#39;t rebuilt is an image that only accumulates known vulnerabilities.&lt;/p&gt;
&lt;p&gt;So the gap isn&amp;#39;t &amp;quot;there are no more Bitnami images.&amp;quot; The gap is &amp;quot;there is no more free, continuously patched, hardened catalog that a small team can just adopt.&amp;quot; That&amp;#39;s the hole QuenchWorks fills.&lt;/p&gt;
&lt;h2&gt;So what is QuenchWorks?&lt;/h2&gt;
&lt;p&gt;QuenchWorks is a security-first, from-scratch replacement for the Bitnami catalog. Right now it ships &lt;strong&gt;over 150 container images and more than 120 Helm charts&lt;/strong&gt;, and it&amp;#39;s growing on a daily build cadence.&lt;/p&gt;
&lt;p&gt;The rules I set for myself on day one:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Every image is built from source.&lt;/strong&gt; Not repackaged, not re-tagged, not &amp;quot;pull the upstream binary and slap a label on it.&amp;quot; The source is compiled inside the build.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero fixable CVEs, enforced by the build itself.&lt;/strong&gt; If a scan finds a vulnerability that has a fix available, the build fails. I&amp;#39;ll come back to the word &amp;quot;fixable&amp;quot; because it matters a lot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimal and locked down by default.&lt;/strong&gt; Nonroot, read-only root filesystem, no shell where one isn&amp;#39;t needed, multi-arch for &lt;code&gt;x86_64&lt;/code&gt; and &lt;code&gt;arm64&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Signed and verifiable.&lt;/strong&gt; Every image is cosign-signed and ships a software bill of materials and build provenance you can check yourself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clean-room.&lt;/strong&gt; QuenchWorks does not copy Bitnami&amp;#39;s charts or configs. It&amp;#39;s an independent implementation, not a fork.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The whole thing lives at &lt;a href=&quot;https://quench-works.com&quot;&gt;quench-works.com&lt;/a&gt;, the images are on GitHub Container Registry, and the charts are published to ArtifactHub as a verified publisher.&lt;/p&gt;
&lt;h2&gt;Why build on Wolfi instead of Debian or Alpine?&lt;/h2&gt;
&lt;p&gt;This is the decision everything else hangs on, so it&amp;#39;s worth explaining.&lt;/p&gt;
&lt;p&gt;Most base images are general-purpose Linux distributions. Debian, Ubuntu, Alpine. They&amp;#39;re built to be a complete operating system you can log into and work in. That&amp;#39;s exactly the problem for a container. A container running Postgres does not need a package manager, a shell, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;wget&lt;/code&gt;, or ninety other packages. Every one of those is more code, and more code means more CVEs that have nothing to do with the app you actually care about.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wolfi&lt;/strong&gt; is different. It&amp;#39;s a distroless-friendly, container-native Linux built by Chainguard specifically to have as little in it as possible and to get security fixes fast. Two tools go with it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;melange&lt;/strong&gt; builds a package from source into a signed APK.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;apko&lt;/strong&gt; assembles a container image from a declarative list of those APKs, with no Dockerfile and no layers full of leftover build tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The payoff is that the final image contains the app, its runtime dependencies, and almost nothing else. There&amp;#39;s no &lt;code&gt;apt&lt;/code&gt;, no busybox shell, no build toolchain hiding in a layer. A smaller image isn&amp;#39;t just faster to pull. It&amp;#39;s a smaller attack surface and a much shorter CVE scan.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the shape of the pipeline for a single app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;   upstream source (a specific, pinned version)
              │
              ▼
        melange build          ← compile from source, CGO off where possible,
              │                   stamp the real version, sign the APK
              ▼
         apko assemble          ← nonroot uid 1001, read-only rootfs,
              │                   multi-arch, only the runtime deps
              ▼
      Trivy scan (the gate)      ← fail the build on ANY fixable CVE
              │
              ▼
   cosign sign + SBOM + SLSA      ← keyless signature, bill of materials,
              │                    build provenance attestation
              ▼
        GHCR, pinned by digest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Trivy step is the one that makes the whole project mean something, so let&amp;#39;s talk about it honestly.&lt;/p&gt;
&lt;h2&gt;What &amp;quot;zero CVE&amp;quot; actually means (and why I refuse to fake it)&lt;/h2&gt;
&lt;p&gt;&amp;quot;Zero CVE&amp;quot; is a phrase people love to put on a marketing page, and most of the time it&amp;#39;s not true. Any non-trivial piece of software has open vulnerabilities somewhere in its dependency graph at any given moment. Anyone who tells you their image has literally zero known vulnerabilities is either not scanning hard enough or not telling you the whole story.&lt;/p&gt;
&lt;p&gt;So here&amp;#39;s the precise claim QuenchWorks makes: &lt;strong&gt;zero fixable CVEs.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The scanner runs in comprehensive mode and I filter to vulnerabilities that have a fix available. If a CVE has a patched version out there, the build must include it or the build fails. No exceptions, no allowlist to sneak something past the gate. That&amp;#39;s the part I control, and I hold it at zero.&lt;/p&gt;
&lt;p&gt;What I can&amp;#39;t control is upstream. If a project depends on a library that has a known CVE and there&amp;#39;s simply no patched release yet, no amount of rebuilding fixes it. The fix doesn&amp;#39;t exist. In that case QuenchWorks reports the unfixable count openly instead of pretending it&amp;#39;s zero. When upstream ships the patch, the nightly rebuild picks it up automatically and the number drops.&lt;/p&gt;
&lt;p&gt;I think that distinction is the most important thing about the project. &amp;quot;Zero fixable CVEs, and here&amp;#39;s the honest count of what&amp;#39;s still unfixable upstream&amp;quot; is a claim you can actually trust and verify. &amp;quot;Zero CVEs&amp;quot; with no asterisk is a claim you should be suspicious of.&lt;/p&gt;
&lt;h2&gt;Signed, documented, and pinned by digest&lt;/h2&gt;
&lt;p&gt;A hardened image you can&amp;#39;t verify is just a hardened image you&amp;#39;re taking on faith. So every QuenchWorks image ships three things beyond the bits themselves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A cosign signature&lt;/strong&gt;, using keyless Sigstore signing. You can verify the image was built by the QuenchWorks pipeline and not swapped out somewhere in transit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An SBOM&lt;/strong&gt;, a software bill of materials in SPDX format that lists exactly what&amp;#39;s inside. When the next big CVE drops, you can grep your SBOMs instead of guessing which images are affected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SLSA provenance&lt;/strong&gt;, an attestation of how and where the image was built.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You verify them with the GitHub CLI:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gh attestation verify \
  oci://ghcr.io/quenchworks/images/postgresql:&amp;lt;version&amp;gt; \
  --owner quenchworks
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in your charts and manifests, images are always &lt;strong&gt;pinned by digest, never by a floating tag&lt;/strong&gt;. A tag like &lt;code&gt;:16&lt;/code&gt; can be moved to point at different bits tomorrow. A digest like &lt;code&gt;@sha256:...&lt;/code&gt; is the content. If the digest matches, you&amp;#39;re running exactly what was signed. This is the difference between &amp;quot;probably the image I tested&amp;quot; and &amp;quot;provably the image I tested.&amp;quot;&lt;/p&gt;
&lt;h2&gt;The Helm charts, and the piece that keeps them consistent&lt;/h2&gt;
&lt;p&gt;Images are half the story. The other half is the 120-plus Helm charts, because that&amp;#39;s how most people actually deploy this stuff.&lt;/p&gt;
&lt;p&gt;The thing I wanted to avoid was 120 charts that each reinvent the same security boilerplate slightly differently. So there&amp;#39;s a shared library chart called &lt;strong&gt;quench-common&lt;/strong&gt; that every application chart depends on. It defines all the cross-cutting pieces in one place: the pod and container security contexts, the labels, how the image digest gets wired in, the probes, the service account handling.&lt;/p&gt;
&lt;p&gt;An individual chart, say the one for SeaweedFS or Tempo, only has to describe what&amp;#39;s actually specific to that app. The hardening comes from the library, so it&amp;#39;s identical everywhere and I fix it in exactly one spot. Every chart is validated in a real &lt;code&gt;kind&lt;/code&gt; cluster before release, published to ArtifactHub with verified-publisher metadata, and pinned to its image by digest.&lt;/p&gt;
&lt;h2&gt;How to actually use it&lt;/h2&gt;
&lt;p&gt;The nice part is there&amp;#39;s almost nothing to learn. If you were pulling Bitnami, you already know the shape of this.&lt;/p&gt;
&lt;p&gt;Pull an image directly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker pull ghcr.io/quenchworks/images/postgresql:&amp;lt;version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or install a chart from the OCI registry:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;helm install my-postgres \
  oci://ghcr.io/quenchworks/charts/postgresql \
  --version &amp;lt;chart-version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Browse the full catalog, with the live CVE count for every image, at &lt;a href=&quot;https://quench-works.com&quot;&gt;quench-works.com&lt;/a&gt;, and find the charts on ArtifactHub under the QuenchWorks publisher.&lt;/p&gt;
&lt;p&gt;Now let&amp;#39;s stop talking about it and actually use it. The rest of this post is hands-on. I&amp;#39;ll build a full observability stack, wire up GitOps so it deploys itself, ship a real application end to end, and keep the whole thing verifiable and zero-CVE over time. Every command and manifest here is real and runs against the live catalog.&lt;/p&gt;
&lt;Notice type=&quot;tip&quot;&gt;
Everything below pins images by digest and verifies signatures before trusting them. If you copy nothing else from this post, copy that habit. A tag tells you what an image is called. A digest tells you what it actually is.
&lt;/Notice&gt;&lt;h2&gt;How do you verify an image before you trust it?&lt;/h2&gt;
&lt;p&gt;Before we deploy anything, let&amp;#39;s do the step almost everyone skips: proving the image is what it claims to be. QuenchWorks signs every image with keyless cosign and attaches an SBOM and SLSA provenance, so you can check all of it in about ten seconds.&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Install the tools you need. You want the GitHub CLI for attestation checks and cosign for signature verification.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# GitHub CLI (attestations live on GHCR)
brew install gh        # macOS / Linuxbrew
# cosign for Sigstore signatures
brew install cosign
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Verify the build provenance. This proves the image was built by the QuenchWorks pipeline in GitHub Actions and not swapped out somewhere along the way.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gh attestation verify \
  oci://ghcr.io/quenchworks/images/postgresql:17.5 \
  --owner quenchworks
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Inspect the software bill of materials. When the next headline CVE drops, you grep this instead of guessing whether you&amp;#39;re affected.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gh attestation verify \
  oci://ghcr.io/quenchworks/images/postgresql:17.5 \
  --owner quenchworks \
  --predicate-type https://spdx.dev/Document \
  --format json | jq &amp;#39;.[].verificationResult.statement.predicate.name&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Resolve the tag to its digest, and use that digest everywhere from now on.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker buildx imagetools inspect \
  ghcr.io/quenchworks/images/postgresql:17.5 \
  --format &amp;#39;{{.Manifest.Digest}}&amp;#39;
# sha256:... &amp;lt;- this is what you pin in values.yaml and manifests
&lt;/code&gt;&lt;/pre&gt;
&lt;/Steps&gt;&lt;Notice type=&quot;warning&quot;&gt;
If `gh attestation verify` fails, do not deploy the image. A failed verification means either the image was tampered with or you&apos;re pointing at something that isn&apos;t a QuenchWorks build. That&apos;s exactly the signal the whole supply chain exists to give you.
&lt;/Notice&gt;&lt;h2&gt;Example 1: A full observability stack you can trust&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s start with the thing every cluster needs and nobody enjoys wiring up: observability. Metrics, logs, and traces, with dashboards on top. The classic Grafana stack is often called LGTM (Loki, Grafana, Tempo, Mimir), and QuenchWorks ships all of the pieces plus an umbrella chart that assembles them.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the data flow we&amp;#39;re building:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;   your apps + kubernetes            collection            storage                    query + view
  ┌─────────────────────┐      ┌──────────────────┐   ┌────────────────────┐      ┌──────────────┐
  │  app metrics /logs   │────▶│  OTel Collector   │──▶│ VictoriaMetrics      │─┐    │              │
  │  traces (OTLP)       │      │  (receivers +     │   │  (metrics, TSDB)     │ │    │              │
  ├─────────────────────┤      │   processors +    │──▶│ Loki (logs)          │ ├──▶│   Grafana    │
  │  node_exporter       │────▶│   exporters)      │   │ Tempo (traces)       │ │    │  dashboards  │
  │  kube-state-metrics  │      │                   │──▶│                      │─┘    │              │
  │  Vector (log tail)   │────▶│                   │   └────────────────────┘      └──────────────┘
  └─────────────────────┘      └──────────────────┘
        all images: nonroot, read-only rootfs, 0 fixable CVEs, pinned by digest
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;What&amp;#39;s in the box&lt;/h3&gt;
&lt;Tabs&gt;
  &lt;Tab name=&quot;Components&quot;&gt;
    The `lgtm-stack` umbrella chart pulls these QuenchWorks charts as dependencies, every one of them a hardened, signed, digest-pinned image:&lt;pre&gt;&lt;code&gt;- **VictoriaMetrics** for metrics storage (a faster, lighter drop-in for Prometheus TSDB)
- **Loki** for logs
- **Tempo** for distributed traces
- **Grafana** for dashboards and querying
- **OTel Collector** as the single ingest point for OTLP metrics, logs, and traces
- **Vector** for tailing and shipping node and pod logs
- **kube-state-metrics** and **node-exporter** for cluster and host metrics
- **Alertmanager** for routing alerts
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;
  &lt;Tab name=&quot;Why these choices&quot;&gt;
    A few opinionated defaults worth calling out:&lt;pre&gt;&lt;code&gt;- **VictoriaMetrics over vanilla Prometheus** for storage. It speaks PromQL, uses far less memory, and handles long retention without falling over. You can still scrape with Prometheus conventions.
- **OTel Collector as the front door.** Everything sends OTLP to one place. If you later swap a backend, your apps don&amp;#39;t change, only the collector&amp;#39;s exporters do.
- **Vector for logs** because it&amp;#39;s a single fast binary with backpressure handling, rather than a JVM log shipper eating a gig of RAM per node.
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;
&lt;/Tabs&gt;&lt;h3&gt;The repository layout&lt;/h3&gt;
&lt;p&gt;I&amp;#39;m going to do this the GitOps way from the start, so here&amp;#39;s the repo we&amp;#39;ll build up across the next two examples:&lt;/p&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;platform-gitops/&lt;ul&gt;
&lt;li&gt;clusters/&lt;ul&gt;
&lt;li&gt;production/&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;kustomization.yaml&lt;/strong&gt; the entry point Argo CD or Flux watches&lt;/li&gt;
&lt;li&gt;observability.yaml the Argo CD Application for this stack&lt;/li&gt;
&lt;li&gt;platform.yaml cert-manager, ingress, external-secrets&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;staging/&lt;ul&gt;
&lt;li&gt;kustomization.yaml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;stacks/&lt;ul&gt;
&lt;li&gt;observability/&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;values.yaml&lt;/strong&gt; the lgtm-stack values we&amp;#39;re about to write&lt;/li&gt;
&lt;li&gt;dashboards/ your own Grafana dashboard JSON&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;platform/&lt;ul&gt;
&lt;li&gt;cert-manager-values.yaml&lt;/li&gt;
&lt;li&gt;ingress-values.yaml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;apps/&lt;ul&gt;
&lt;li&gt;acme-web/&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;values.yaml&lt;/strong&gt; the app we ship in example 3&lt;/li&gt;
&lt;li&gt;database.yaml postgresql + redis&lt;/li&gt;
&lt;li&gt;ingress.yaml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;README.md&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;h3&gt;Step by step: install the stack&lt;/h3&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Create a namespace for everything observability-related.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create namespace observability
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Write the stack&amp;#39;s values. This is the real shape of &lt;code&gt;lgtm-stack&lt;/code&gt; values, with the toggles that matter for a first install.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Grafana: the front end. Stateless by design; dashboards come from config.
grafana:
  enabled: true
  adminPassword: &amp;quot;&amp;quot; # leave empty, pull from a secret (see example 3)
  persistence:
    enabled: false # dashboards are provisioned, not hand-drawn
  ingress:
    enabled: true
    hostname: grafana.internal.example.com

# Metrics storage. PromQL-compatible, memory-friendly.
victoriametrics:
  enabled: true
  retentionPeriod: 30d
  persistence:
    enabled: true
    size: 50Gi

# Logs.
loki:
  enabled: true
  persistence:
    enabled: true
    size: 50Gi

# Traces.
tempo:
  enabled: true
  persistence:
    enabled: true
    size: 20Gi

# The single ingest point for OTLP metrics, logs, and traces.
otelCollector:
  enabled: true

# Log shipping from every node.
vector:
  enabled: true

# Cluster + host metrics.
kubeStateMetrics:
  enabled: true
nodeExporter:
  enabled: true

# Alert routing.
alertmanager:
  enabled: true

# Provision your own dashboards from JSON in the repo.
dashboards:
  enabled: true
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Install the umbrella chart from the OCI registry, pointing at your values.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;helm install lgtm \
  oci://ghcr.io/quenchworks/charts/lgtm-stack \
  --version 0.1.0 \
  --namespace observability \
  --values stacks/observability/values.yaml \
  --wait
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Confirm everything reached Ready.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl -n observability get pods
kubectl -n observability rollout status deploy/lgtm-grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Port-forward Grafana and log in. The metrics, logs, and traces data sources are already wired to VictoriaMetrics, Loki, and Tempo.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl -n observability port-forward svc/lgtm-grafana 3000:3000
# http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;
&lt;/Steps&gt;&lt;Notice type=&quot;note&quot;&gt;
The values above are the ones you&apos;ll touch on day one. For the full schema, run `helm show values oci://ghcr.io/quenchworks/charts/lgtm-stack --version 0.1.0`. Every sub-chart also installs on its own if you&apos;d rather compose the stack yourself.
&lt;/Notice&gt;&lt;h3&gt;Sending data to the collector&lt;/h3&gt;
&lt;p&gt;Your apps point at one endpoint, the OTel Collector, using standard OTLP. Nothing app-side is QuenchWorks-specific, which is the point.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;env:
  - name: OTEL_EXPORTER_OTLP_ENDPOINT
    value: &amp;quot;http://lgtm-otel-collector.observability.svc:4317&amp;quot;
  - name: OTEL_EXPORTER_OTLP_PROTOCOL
    value: &amp;quot;grpc&amp;quot;
  - name: OTEL_SERVICE_NAME
    value: &amp;quot;acme-web&amp;quot;
  - name: OTEL_RESOURCE_ATTRIBUTES
    value: &amp;quot;deployment.environment=production&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&amp;#39;s a minimal collector config that fans OTLP out to all three backends:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;receivers:
  otlp:
    protocols:
      grpc: { endpoint: 0.0.0.0:4317 }
      http: { endpoint: 0.0.0.0:4318 }

processors:
  batch: {}
  memory_limiter:
    check_interval: 5s
    limit_percentage: 80

exporters:
  otlphttp/metrics:
    endpoint: http://lgtm-victoriametrics.observability.svc:8428/opentelemetry
  loki:
    endpoint: http://lgtm-loki.observability.svc:3100/loki/api/v1/push
  otlp/tempo:
    endpoint: lgtm-tempo.observability.svc:4317
    tls: { insecure: true }

service:
  pipelines:
    metrics: { receivers: [otlp], processors: [memory_limiter, batch], exporters: [otlphttp/metrics] }
    logs:    { receivers: [otlp], processors: [memory_limiter, batch], exporters: [loki] }
    traces:  { receivers: [otlp], processors: [memory_limiter, batch], exporters: [otlp/tempo] }
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Common questions&lt;/h3&gt;
&lt;Accordion client:load title=&quot;Why VictoriaMetrics instead of Prometheus for storage?&quot;&gt;
Prometheus is a great scraper and a mediocre long-term store. VictoriaMetrics speaks the same PromQL and remote-write protocol, uses a fraction of the memory, and handles months of retention without sharding gymnastics. You keep the Prometheus ecosystem and lose the operational pain. If you specifically want the Prometheus server, that chart is in the catalog too.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Where does my data actually live?&quot;&gt;
In PersistentVolumes, sized by the `persistence.size` values you set. VictoriaMetrics, Loki, and Tempo each get their own PVC. Grafana is deliberately stateless: its dashboards are provisioned from JSON in your Git repo, so a Grafana pod can be deleted and recreated with zero data loss. That&apos;s a feature, not a limitation.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;How do I add my own dashboards?&quot;&gt;
Drop the dashboard JSON into `stacks/observability/dashboards/` in your repo and reference it through the `dashboards` values. Because Grafana is stateless and provisioned, your dashboards are code, reviewed in pull requests like everything else, and they survive pod restarts.
&lt;/Accordion&gt;&lt;h2&gt;Example 2: CI/CD and GitOps that deploys itself&lt;/h2&gt;
&lt;p&gt;A stack you install by hand is a stack that drifts. The fix is GitOps: your Git repo is the single source of truth, and a controller in the cluster continuously reconciles reality against what&amp;#39;s committed. You don&amp;#39;t run &lt;code&gt;helm install&lt;/code&gt; from your laptop anymore. You open a pull request.&lt;/p&gt;
&lt;p&gt;The difference from traditional push-based CI/CD is worth stating plainly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;  PUSH model (traditional)                 PULL model (GitOps)
  ┌──────────┐   kubectl/helm              ┌──────────┐   commit
  │  CI job   │ ───────────────▶ cluster   │  Git repo │ ◀─────────── you
  └──────────┘   (credentials                └──────────┘
                  live in CI)                     ▲ watches + reconciles
                                                  │
                                             ┌──────────────┐
                                             │ Argo CD/Flux  │ (in-cluster)
                                             └──────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the pull model your CI never needs cluster credentials. The in-cluster controller pulls. That&amp;#39;s a real security win, and it pairs perfectly with digest-pinned, signed images.&lt;/p&gt;
&lt;h3&gt;Bootstrap the controller&lt;/h3&gt;
&lt;Tabs&gt;
  &lt;Tab name=&quot;Argo CD&quot;&gt;
    Argo CD watches your Git repo and applies what&apos;s there. Install it, then point it at the repo with an `Application` per stack.&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create namespace argocd
kubectl apply -n argocd \
  -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An &lt;code&gt;Application&lt;/code&gt; that deploys our observability stack straight from the QuenchWorks OCI registry, with values from Git:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: observability
  namespace: argocd
spec:
  project: default
  sources:
    # The hardened chart, pinned to an exact version
    - repoURL: ghcr.io/quenchworks/charts
      chart: lgtm-stack
      targetRevision: 0.1.0
      helm:
        valueFiles:
          - $values/stacks/observability/values.yaml
    # Your Git repo, providing the values file above
    - repoURL: https://github.com/your-org/platform-gitops
      targetRevision: main
      ref: values
  destination:
    server: https://kubernetes.default.svc
    namespace: observability
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;
  &lt;Tab name=&quot;Flux&quot;&gt;
    Flux does the same job with a set of custom resources. You declare where the chart lives and where the values come from, and Flux reconciles.&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;flux bootstrap github \
  --owner=your-org \
  --repository=platform-gitops \
  --branch=main \
  --path=clusters/production
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
  name: lgtm-stack
  namespace: flux-system
spec:
  interval: 10m
  url: oci://ghcr.io/quenchworks/charts/lgtm-stack
  ref:
    tag: 0.1.0
---
apiVersion: helm.toolkit.fluxcd.io/v2beta2
kind: HelmRelease
metadata:
  name: observability
  namespace: observability
spec:
  interval: 10m
  chartRef:
    kind: OCIRepository
    name: lgtm-stack
    namespace: flux-system
  valuesFrom:
    - kind: ConfigMap
      name: observability-values
  install:
    createNamespace: true
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;
&lt;/Tabs&gt;&lt;h3&gt;The CI half: verify before you promote&lt;/h3&gt;
&lt;p&gt;GitOps handles deployment. CI&amp;#39;s job shrinks to something healthier: lint the manifests, render them, and above all verify the image signature before letting a digest into the repo. Here&amp;#39;s a GitHub Actions workflow that does exactly that.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: verify-and-render
on:
  pull_request:
    paths: [&amp;quot;stacks/**&amp;quot;, &amp;quot;apps/**&amp;quot;, &amp;quot;clusters/**&amp;quot;]

jobs:
  verify:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write # for keyless verification
    steps:
      - uses: actions/checkout@v4

      - name: Install tooling
        run: |
          curl -sSfL https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 \
            -o /usr/local/bin/cosign &amp;amp;&amp;amp; chmod +x /usr/local/bin/cosign
          curl -sL https://get.helm.sh/helm-v3.16.0-linux-amd64.tar.gz | tar xz
          sudo mv linux-amd64/helm /usr/local/bin/

      - name: Verify every QuenchWorks image referenced in this PR
        run: |
          # pull the digests out of the values and prove each one is signed
          grep -rhoE &amp;#39;ghcr.io/quenchworks/images/[a-z0-9-]+@sha256:[a-f0-9]+&amp;#39; stacks apps \
            | sort -u \
            | while read -r ref; do
                echo &amp;quot;Verifying $ref&amp;quot;
                gh attestation verify &amp;quot;oci://$ref&amp;quot; --owner quenchworks
              done
        env:
          GH_TOKEN: ${{ github.token }}

      - name: Render the charts (catch template errors before merge)
        run: |
          helm template observability \
            oci://ghcr.io/quenchworks/charts/lgtm-stack --version 0.1.0 \
            --values stacks/observability/values.yaml &amp;gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;
&lt;Notice type=&quot;tip&quot;&gt;
The verify step is the one that earns its keep. It makes an unsigned or tampered image a merge blocker, not a production incident. The whole supply chain QuenchWorks builds is only worth anything if something actually checks it, and this is where you check it.
&lt;/Notice&gt;&lt;h3&gt;Keeping digests fresh automatically&lt;/h3&gt;
&lt;p&gt;Pinning by digest is great for reproducibility and terrible for staying current, unless you automate the bumps. Renovate does this. It watches the registry, opens a pull request when a new digest ships, and your CI verifies the signature on that new digest before you merge. QuenchWorks has a hardened Renovate image in the catalog, so you can even run the bot on your own hardened base.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;$schema&amp;quot;: &amp;quot;https://docs.renovatebot.com/renovate-schema.json&amp;quot;,
  &amp;quot;extends&amp;quot;: [&amp;quot;config:recommended&amp;quot;],
  &amp;quot;helm-values&amp;quot;: { &amp;quot;managerFilePatterns&amp;quot;: [&amp;quot;/values\\.yaml$/&amp;quot;] },
  &amp;quot;packageRules&amp;quot;: [
    {
      &amp;quot;matchDatasources&amp;quot;: [&amp;quot;docker&amp;quot;],
      &amp;quot;matchPackagePatterns&amp;quot;: [&amp;quot;^ghcr.io/quenchworks/&amp;quot;],
      &amp;quot;pinDigests&amp;quot;: true,
      &amp;quot;groupName&amp;quot;: &amp;quot;quenchworks images&amp;quot;
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;GitOps questions people actually ask&lt;/h3&gt;
&lt;Accordion client:load title=&quot;How do I roll back a bad deploy?&quot;&gt;
You revert the commit. That&apos;s the whole answer, and it&apos;s why GitOps is worth the setup. The controller sees the repo change back to the previous digest and reconciles the cluster to match. No frantic `helm rollback` from memory, no wondering what state the cluster is in. Git history is your deploy history.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Doesn&apos;t pinning by digest mean I&apos;m always out of date?&quot;&gt;
Only if you don&apos;t automate it. With Renovate opening digest-bump PRs and CI verifying each new digest&apos;s signature, you get the best of both: every deploy is reproducible and provable, and you&apos;re never more than a merged PR behind the latest hardened build. Reproducibility and freshness stop being a trade-off.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Why keep cluster credentials out of CI?&quot;&gt;
Because CI is the most attacked part of most pipelines. In the push model, a compromised CI job has the keys to your cluster. In the pull model, the in-cluster controller reaches out to Git and the registry, and CI only ever touches your repo. There&apos;s no cluster credential to steal from CI because there isn&apos;t one there.
&lt;/Accordion&gt;&lt;h2&gt;Example 3: Shipping a real application end to end&lt;/h2&gt;
&lt;p&gt;Enough infrastructure. Let&amp;#39;s deploy an actual app with a database, a cache, TLS, and network isolation, using QuenchWorks charts for every piece. Call it &lt;code&gt;acme-web&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The moving parts:&lt;/p&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;apps/acme-web/&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;values.yaml&lt;/strong&gt; the app itself&lt;/li&gt;
&lt;li&gt;database.yaml postgresql, digest-pinned&lt;/li&gt;
&lt;li&gt;cache.yaml redis&lt;/li&gt;
&lt;li&gt;secrets.yaml external-secrets pulling from your vault&lt;/li&gt;
&lt;li&gt;ingress.yaml ingress-nginx route + cert-manager TLS&lt;/li&gt;
&lt;li&gt;networkpolicy.yaml default-deny + explicit allows&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Create the namespace and a default-deny NetworkPolicy. Start locked down, then open only what&amp;#39;s needed. Every QuenchWorks image already runs nonroot with a read-only root filesystem, so the network is the next layer to harden.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: acme
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: web-to-db
  namespace: acme
spec:
  podSelector:
    matchLabels: { app.kubernetes.io/name: postgresql }
  ingress:
    - from:
        - podSelector:
            matchLabels: { app.kubernetes.io/name: acme-web }
      ports:
        - port: 5432
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Pull secrets from your vault with external-secrets instead of committing them. The database password never touches Git.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: acme-db
  namespace: acme
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: acme-db-credentials
  data:
    - secretKey: password
      remoteRef:
        key: secret/acme/db
        property: password
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Deploy PostgreSQL, pinned by digest, reading its password from that secret.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;helm install acme-db \
  oci://ghcr.io/quenchworks/charts/postgresql \
  --namespace acme --create-namespace \
  --set auth.existingSecret=acme-db-credentials \
  --set primary.persistence.size=20Gi \
  --wait
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Deploy Redis for caching and sessions.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;helm install acme-cache \
  oci://ghcr.io/quenchworks/charts/redis \
  --namespace acme \
  --set auth.enabled=true \
  --set master.persistence.size=8Gi \
  --wait
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Deploy the app, wiring it to both. This is where you&amp;#39;d point at your own application image; the pattern is identical.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;image:
  repository: ghcr.io/your-org/acme-web
  # your app&amp;#39;s own digest; the QuenchWorks charts pin theirs the same way
  digest: &amp;quot;sha256:...&amp;quot;

replicaCount: 3

extraEnvVars:
  - name: DATABASE_HOST
    value: acme-db-postgresql.acme.svc
  - name: DATABASE_PASSWORD
    valueFrom:
      secretKeyRef:
        name: acme-db-credentials
        key: password
  - name: REDIS_HOST
    value: acme-cache-redis-master.acme.svc

# QuenchWorks charts default to a locked-down security context.
# You inherit nonroot + read-only rootfs; declare writable scratch explicitly.
extraVolumes:
  - name: tmp
    emptyDir: {}
extraVolumeMounts:
  - name: tmp
    mountPath: /tmp
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Expose it with ingress-nginx and get an automatic TLS cert from cert-manager.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: acme-web
  namespace: acme
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts: [app.example.com]
      secretName: acme-web-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: acme-web
                port: { number: 8080 }
&lt;/code&gt;&lt;/pre&gt;
&lt;/Steps&gt;&lt;Notice type=&quot;note&quot;&gt;
Notice what you did not have to do: no `runAsUser`, no `readOnlyRootFilesystem`, no dropping capabilities by hand. The QuenchWorks charts set all of that through the shared `quench-common` library, so every workload starts hardened and you only declare the exceptions, like the writable `/tmp` above. Secure by default, not secure if you remember.
&lt;/Notice&gt;&lt;h2&gt;Example 4: Staying zero-CVE after day one&lt;/h2&gt;
&lt;p&gt;The hard part of a secure catalog isn&amp;#39;t launch day. It&amp;#39;s day ninety, when new CVEs have been found in software you already deployed. Here&amp;#39;s how the whole system stays honest without you babysitting it.&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;&lt;p&gt;QuenchWorks rebuilds every image on a nightly schedule against a fresh vulnerability database. When upstream ships a fix, the next rebuild picks it up and the image&amp;#39;s fixable-CVE count stays at zero on its own.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;New digests land in GHCR, signed and attested exactly like the originals.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Renovate (from example 2) opens a pull request bumping the digest in your Git repo.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your CI verifies the new digest&amp;#39;s signature and provenance before the PR can merge.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Argo CD or Flux reconciles the merged change into the cluster. You went from an upstream patch to a verified, deployed fix without a human touching a cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/Steps&gt;&lt;p&gt;That loop is the actual product. Not any single image, but a pipeline where a security fix flows from upstream to your running pods through a chain that&amp;#39;s signed and checked at every hop.&lt;/p&gt;
&lt;p&gt;&lt;Card
  title=&quot;Browse the full QuenchWorks catalog&quot;
  image=&quot;https://raw.githubusercontent.com/quenchworks/.github/main/profile/assets/chart-icon.png&quot;
  subtitle=&quot;150+ images · 120+ charts · verified publisher&quot;
  description=&quot;Every image with its live CVE count, plus install commands for each chart.&quot;
  link=&quot;https://quench-works.com&quot;
/&gt;&lt;/p&gt;
&lt;h2&gt;Where it stands, honestly&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ll close the way I started, without the marketing gloss.&lt;/p&gt;
&lt;p&gt;QuenchWorks is real and it&amp;#39;s running. The daily cadence keeps adding apps, the nightly rebuild keeps the CVE counts honest, and the whole supply chain is signed and verifiable today. It is not a company and it is not trying to sell you a subscription. It exists because a useful free thing got taken away and rebuilding it turned out to be a genuinely interesting engineering problem in supply-chain security.&lt;/p&gt;
&lt;p&gt;A few things are still upstream-blocked, where a project ships a dependency that nobody has patched yet. Those show up in the catalog with their real numbers rather than hidden. When upstream moves, the rebuild catches up on its own.&lt;/p&gt;
&lt;p&gt;If you lost your Bitnami images and you&amp;#39;ve been putting off dealing with it, this is a drop-in place to land. And if you just care about how you build a container catalog that can prove what&amp;#39;s inside it, that&amp;#39;s the part I&amp;#39;d love to talk about.&lt;/p&gt;
&lt;p&gt;You can find everything at &lt;a href=&quot;https://quench-works.com&quot;&gt;quench-works.com&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>DevOps</category><category>Containers</category><category>Supply Chain Security</category><category>Kubernetes</category><category>Open Source</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0105-quenchworks-zero-cve-bitnami-alternative-wolfi/hero.png" length="0" type="image/jpeg"/></item><item><title>Dotfiles: A Git-Based Strategy for Configuration Management</title><link>https://mkabumattar.com/blog/post/dotfiles/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/dotfiles/</guid><description>Discover the ultimate strategy for managing your dotfiles using a bare Git repository, simplifying the process of keeping your configuration files synchronized and secure across multiple machines.</description><pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Your dotfiles those hidden &lt;code&gt;.&lt;/code&gt;-prefixed configuration files scattered across your home directory are the muscle memory of your environment. They hold your shell aliases, your editor settings, your Git identity, your terminal theme. Lose them and a fresh machine feels like someone else&amp;#39;s computer. Version them, and any machine becomes &lt;em&gt;yours&lt;/em&gt; in a single clone.&lt;/p&gt;
&lt;p&gt;This guide covers two battle-tested, Git-based strategies for managing them:&lt;/p&gt;
&lt;Notice type=&quot;info&quot;&gt;
  Both approaches use plain Git no extra runtime, no proprietary format. They
  differ only in **how the files reach your home directory**: the bare
  repository checks them out in place, while the modular repository symlinks
  them in from a clone you control.
&lt;/Notice&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;How files land in &lt;code&gt;$HOME&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Best when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bare Git repository&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Checked out directly into home&lt;/td&gt;
&lt;td&gt;You want zero tooling and zero symlinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Modular repo + bootstrap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Symlinked from a normal clone&lt;/td&gt;
&lt;td&gt;You want modularity, opt-in modules, and man pages&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Pick whichever fits your taste both are shown below in full.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;You&amp;#39;ll be pushing your configuration to a private remote, so set up SSH first if you haven&amp;#39;t. My companion guide walks through it end to end: &lt;a href=&quot;/blog/post/git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux&quot;&gt;Git SSH Keys for GitHub, GitLab, and Bitbucket on Linux&lt;/a&gt;. New to the shell in general? Start with &lt;a href=&quot;/blog/post/introduction-to-linux-cli&quot;&gt;Introduction to Linux CLI&lt;/a&gt;.&lt;/p&gt;
&lt;Notice type=&quot;tip&quot;&gt;&lt;p&gt;Set your Git identity before committing anything, so the history is attributed correctly from the very first commit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git config --global user.name &amp;#39;YOUR_NAME&amp;#39;
git config --global user.email &amp;#39;YOUR_EMAIL@EXAMPLE.COM&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;/Notice&gt;&lt;h2&gt;Strategy 1: The bare Git repository&lt;/h2&gt;
&lt;p&gt;The classic trick: initialize a &lt;strong&gt;bare&lt;/strong&gt; repository in a discrete folder (&lt;code&gt;$HOME/.dotfiles&lt;/code&gt;) and point its work-tree at &lt;code&gt;$HOME&lt;/code&gt;. No symlinks, no copying your real home directory &lt;em&gt;becomes&lt;/em&gt; the work-tree.&lt;/p&gt;
&lt;h3&gt;Initial setup&lt;/h3&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Create a bare Git repository in your home directory:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git init --bare $HOME/.dotfiles
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Add a &lt;code&gt;config&lt;/code&gt; alias to your shell profile so you can run Git against that repo from anywhere. Pick the tab for your shell:&lt;/li&gt;
&lt;/ol&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Bash&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;alias config=&amp;#39;git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Zsh&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;alias config=&amp;#39;git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Tell Git not to show every untracked file in &lt;code&gt;$HOME&lt;/code&gt; (which would be thousands), so &lt;code&gt;config status&lt;/code&gt; stays readable:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;config config --local status.showUntrackedFiles no
&lt;/code&gt;&lt;/pre&gt;
&lt;/Steps&gt;&lt;p&gt;With the &lt;code&gt;config&lt;/code&gt; alias in place, you now drive your dotfiles with ordinary Git commands just type &lt;code&gt;config&lt;/code&gt; where you&amp;#39;d normally type &lt;code&gt;git&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Adding and committing dotfiles&lt;/h3&gt;
&lt;p&gt;Version-controlling a file is exactly like a normal repo, using &lt;code&gt;config&lt;/code&gt; instead of &lt;code&gt;git&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;config add .vimrc .bashrc .zshrc
config commit -m &amp;#39;Add shell and editor config&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then publish to a private remote for safekeeping and easy sync. Use the &lt;strong&gt;SSH&lt;/strong&gt; remote so you never type credentials:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;config remote add origin git@github.com:YOUR_USERNAME/dotfiles.git
config branch -M main
config push -u origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;Notice type=&quot;warning&quot;&gt;
  Treat this repo like any other public-facing thing: **never commit secrets**.
  Keep API tokens, SSH private keys, and `.netrc`-style credentials out of it
  add them to a `.gitignore` (tracked in the repo) before your first push.
&lt;/Notice&gt;&lt;h3&gt;Replicating your environment on a new machine&lt;/h3&gt;
&lt;p&gt;On a fresh box, add the &lt;code&gt;config&lt;/code&gt; alias to your shell profile, then clone the repo as &lt;strong&gt;bare&lt;/strong&gt; into &lt;code&gt;$HOME/.dotfiles&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git clone --bare git@github.com:YOUR_USERNAME/dotfiles.git $HOME/.dotfiles
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now check the files out into &lt;code&gt;$HOME&lt;/code&gt;. If files like &lt;code&gt;.bashrc&lt;/code&gt; already exist, Git refuses to overwrite them this one-liner backs up any conflicts, then checks out cleanly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mkdir -p .dotfiles-backup &amp;amp;&amp;amp; \
config checkout 2&amp;gt;&amp;amp;1 | egrep &amp;quot;\s+\.&amp;quot; | awk &amp;#39;{print $1}&amp;#39; | \
xargs -I{} mv {} .dotfiles-backup/{}
config checkout -f
config config --local status.showUntrackedFiles no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s it your environment is restored, and &lt;code&gt;config status&lt;/code&gt; is clean.&lt;/p&gt;
&lt;h2&gt;Strategy 2: A modular repo + a bootstrap script&lt;/h2&gt;
&lt;p&gt;The bare-repo trick is elegant, but everything lives as one flat checkout. Once your config grows aliases, shell functions, plugins, per-app configs, even your own CLI tools you&amp;#39;ll want &lt;strong&gt;structure&lt;/strong&gt; and &lt;strong&gt;opt-in modules&lt;/strong&gt;. The approach I actually run does exactly that: a normal Git repo of organized modules, symlinked into place by an idempotent &lt;code&gt;setup&lt;/code&gt; script.&lt;/p&gt;
&lt;p&gt;You can browse the real thing here: &lt;a href=&quot;https://github.com/MKAbuMattar/dotfiles&quot;&gt;github.com/MKAbuMattar/dotfiles&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Repository layout&lt;/h3&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;dotfiles/&lt;ul&gt;
&lt;li&gt;.aliases/ per-tool alias modules (35 modules)&lt;/li&gt;
&lt;li&gt;.utils/ per-tool shell function libraries (17 modules)&lt;/li&gt;
&lt;li&gt;.plugins/ zsh plugins + Python CLI plugins&lt;/li&gt;
&lt;li&gt;.zsh/ core zsh settings (options, completion, keybindings)&lt;/li&gt;
&lt;li&gt;.config/ third-party app configs (kitty, btop, mpv, …)&lt;/li&gt;
&lt;li&gt;.docs/ markdown man-page sources (the source of truth)&lt;/li&gt;
&lt;li&gt;.man/ generated roff man pages&lt;/li&gt;
&lt;li&gt;.scripts/ build &amp;amp; maintenance scripts&lt;/li&gt;
&lt;li&gt;.agents/ Claude Code skills used to author this repo&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.zshrc&lt;/strong&gt; the entry point you opt modules in/out from&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;setup&lt;/strong&gt; one-shot bootstrap (idempotent; safe to re-run)&lt;/li&gt;
&lt;li&gt;README.md&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;p&gt;Instead of dumping files in &lt;code&gt;$HOME&lt;/code&gt;, each subtree is &lt;strong&gt;symlinked&lt;/strong&gt; into &lt;code&gt;~/.config/.dotfiles&lt;/code&gt;, and &lt;code&gt;~/.zshrc&lt;/code&gt; is symlinked to the repo&amp;#39;s &lt;code&gt;.zshrc&lt;/code&gt;. The clone stays the single source of truth edit a file in the repo and your live config updates instantly, because it &lt;em&gt;is&lt;/em&gt; the same file.&lt;/p&gt;
&lt;h3&gt;Quick start&lt;/h3&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Clone the repository somewhere stable (not directly in &lt;code&gt;$HOME&lt;/code&gt;):&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git clone git@github.com:MKAbuMattar/dotfiles.git ~/Work/dotfiles
cd ~/Work/dotfiles
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Run the bootstrap script. It&amp;#39;s idempotent re-running it detects existing correct symlinks and skips them, and prompts before overwriting anything else:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;./setup
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Reload your shell (or just open a new terminal):&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;source ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;
&lt;/Steps&gt;&lt;p&gt;Here&amp;#39;s roughly what a first run looks like:&lt;/p&gt;
&lt;p&gt;&amp;lt;Terminal
  client:load
  title=&amp;quot;zsh&amp;quot;
  lines={[
    &amp;#39;$ ./setup&amp;#39;,
    &amp;#39;✔ linked  ~/.config/.dotfiles → ~/Work/dotfiles&amp;#39;,
    &amp;#39;✔ linked  ~/.zshrc → ~/.config/.dotfiles/.zshrc&amp;#39;,
    &amp;#39;✔ gitconfig [include] block written (12 modules)&amp;#39;,
    &amp;#39;✔ man pages built → .man/man1, .man/man7&amp;#39;,
    &amp;#39;✔ apropos index refreshed (mandb)&amp;#39;,
    &amp;#39;✔ tool check: git ✓  zsh ✓&amp;#39;,
    &amp;#39;Done. Run: source ~/.zshrc&amp;#39;,
  ]}
/&amp;gt;&lt;/p&gt;
&lt;h3&gt;What the bootstrap does&lt;/h3&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Symlinks&lt;/strong&gt; the repo (or its individual subtrees) into &lt;code&gt;~/.config/.dotfiles&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Links&lt;/strong&gt; &lt;code&gt;~/.zshrc&lt;/code&gt; to the repo&amp;#39;s &lt;code&gt;.zshrc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Builds&lt;/strong&gt; a modular &lt;code&gt;~/.gitconfig&lt;/code&gt; &lt;code&gt;[include]&lt;/code&gt; block from every &lt;code&gt;*.gitconfig&lt;/code&gt; shipped in &lt;code&gt;.config/gitconfig/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generates&lt;/strong&gt; the man pages from &lt;code&gt;.docs/&lt;/code&gt; and refreshes the &lt;code&gt;apropos&lt;/code&gt; index.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verifies&lt;/strong&gt; that &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;zsh&lt;/code&gt; are installed, and &lt;strong&gt;backs up&lt;/strong&gt; any pre-existing non-symlink target before replacing it.&lt;/li&gt;
&lt;/ol&gt;
&lt;/Steps&gt;&lt;Notice type=&quot;note&quot;&gt;
  Because the bootstrap only ever creates symlinks and backs up conflicts before
  touching them, it&apos;s safe to re-run after every `git pull` no clobbering, no
  surprises.
&lt;/Notice&gt;&lt;h3&gt;Opting modules in and out&lt;/h3&gt;
&lt;p&gt;The payoff of a modular layout: you choose what loads. The arrays in &lt;a href=&quot;https://github.com/MKAbuMattar/dotfiles/blob/main/.zshrc&quot;&gt;&lt;code&gt;.zshrc&lt;/code&gt;&lt;/a&gt; are the control panel comment a line out and that module simply doesn&amp;#39;t load:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zsh&quot;&gt;UTILS=(&amp;quot;clipboard&amp;quot; &amp;quot;fedora&amp;quot; &amp;quot;git&amp;quot; &amp;quot;npm&amp;quot; &amp;quot;python&amp;quot;)    # shell functions
PLUGINS=(&amp;quot;aws&amp;quot; &amp;quot;docker&amp;quot; &amp;quot;fzf&amp;quot; &amp;quot;git&amp;quot; &amp;quot;kubectl&amp;quot;)       # completion / integration
ALIASES=(&amp;quot;docker&amp;quot; &amp;quot;exa&amp;quot; &amp;quot;general&amp;quot; &amp;quot;git&amp;quot; &amp;quot;npm&amp;quot;)       # short command aliases
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After editing, reload with &lt;Kbd&gt;Ctrl&lt;/Kbd&gt; + &lt;Kbd&gt;C&lt;/Kbd&gt; then &lt;code&gt;source ~/.zshrc&lt;/code&gt;, or just open a new terminal.&lt;/p&gt;
&lt;h3&gt;Self-documenting: man pages for everything&lt;/h3&gt;
&lt;p&gt;Every module ships an AWS-style markdown man page, compiled to real roff pages so &lt;code&gt;man &amp;lt;module&amp;gt;&lt;/code&gt; and &lt;code&gt;apropos &amp;lt;keyword&amp;gt;&lt;/code&gt; work for your own config exactly like they do for system tools:&lt;/p&gt;
&lt;p&gt;&amp;lt;Terminal
  client:load
  title=&amp;quot;zsh&amp;quot;
  lines={[
    &amp;#39;$ man git-utils          # your own util module, section 7&amp;#39;,
    &amp;#39;$ apropos kubernetes     # search every page NAME line&amp;#39;,
    &amp;#39;helm-aliases(7)    - Helm command aliases&amp;#39;,
    &amp;#39;kubectl-aliases(7) - kubectl command aliases&amp;#39;,
    &amp;#39;kubectl-plugin(7)  - kubectl completion + helpers&amp;#39;,
    &amp;#39;$ apropos pacman&amp;#39;,
    &amp;#39;arch-aliases(7)    - Arch pacman aliases&amp;#39;,
    &amp;#39;arch-utils(7)      - Arch package helper functions&amp;#39;,
  ]}
/&amp;gt;&lt;/p&gt;
&lt;h3&gt;Built against reusable skills&lt;/h3&gt;
&lt;p&gt;The scripts in this repo aren&amp;#39;t ad-hoc. The &lt;code&gt;setup&lt;/code&gt; bootstrap and the Python CLI tools are written against two &lt;strong&gt;agent skills&lt;/strong&gt; I maintain shared specs that encode strict Bash and Python patterns plus a validator, so quality stays consistent across machines and contributors. You can grab both for your own scripting from my skills repository: &lt;strong&gt;&lt;a href=&quot;https://github.com/MKAbuMattar/skills&quot;&gt;github.com/MKAbuMattar/skills&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;linux-script-developer&lt;/code&gt;&lt;/strong&gt; strict Bash patterns + a validator the &lt;code&gt;setup&lt;/code&gt; script passes at 100%.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;python-script-developer&lt;/code&gt;&lt;/strong&gt; strict Python patterns + a validator every shipped Python plugin passes at 100%.&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;info&quot;&gt;
  Want the same guardrails on your own scripts? Pull the skills from
  [github.com/MKAbuMattar/skills](https://github.com/MKAbuMattar/skills) they&apos;re
  the exact specs (patterns + validators) the `setup` script and every Python
  plugin in the dotfiles are built and checked against.
&lt;/Notice&gt;&lt;p&gt;If you fork the dotfiles and add a script, run the matching validator to keep it in line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;bash    .agents/skills/linux-script-developer/scripts/validate-script.sh  ./your-script.sh
python3 .agents/skills/python-script-developer/scripts/validate-script.py ./your-script.py
&lt;/code&gt;&lt;/pre&gt;
&lt;Notice type=&quot;tip&quot;&gt;
  Once your shell is dialed in, give the terminal itself some polish a prompt,
  colors, icons. My guide on
  [customizing the terminal with Starship](/blog/post/customization-windows-terminal-with-starship)
  pairs perfectly with a modular dotfiles setup.
&lt;/Notice&gt;&lt;h2&gt;Which should you choose?&lt;/h2&gt;
&lt;Accordion client:load title=&quot;I just want my configs versioned with zero fuss&quot;&gt;&lt;p&gt;Use the &lt;strong&gt;bare Git repository&lt;/strong&gt; (Strategy 1). There&amp;#39;s nothing to install and nothing to symlink your home directory is the work-tree, and &lt;code&gt;config&lt;/code&gt; is just &lt;code&gt;git&lt;/code&gt; with a different &lt;code&gt;--git-dir&lt;/code&gt;. It&amp;#39;s the fastest path from &amp;quot;unmanaged&amp;quot; to &amp;quot;versioned and synced.&amp;quot;&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;My config is large and I want opt-in modules&quot;&gt;&lt;p&gt;Use the &lt;strong&gt;modular repo + bootstrap&lt;/strong&gt; (Strategy 2). Splitting aliases, functions, plugins, and app configs into separate files keeps everything navigable, and a &lt;code&gt;setup&lt;/code&gt; script makes a new machine reproducible in one command. The symlink model also means editing the repo updates your live config instantly.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Can I migrate from bare to modular later?&quot;&gt;&lt;p&gt;Yes. Your files are already in Git either way. Move them into a structured layout, write (or borrow) a &lt;code&gt;setup&lt;/code&gt; script that symlinks them, and point your shell at the new location. Nothing about the bare approach locks you in.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;How do I keep secrets out of a public dotfiles repo?&quot;&gt;&lt;p&gt;Never commit credentials. Keep a tracked &lt;code&gt;.gitignore&lt;/code&gt; that excludes things like &lt;code&gt;~/.ssh/id_*&lt;/code&gt;, &lt;code&gt;.netrc&lt;/code&gt;, and any &lt;code&gt;*.env&lt;/code&gt; files, and load real secrets from a separate, untracked file your shell sources only if it exists (e.g. &lt;code&gt;[[ -f ~/.secrets ]] &amp;amp;&amp;amp; source ~/.secrets&lt;/code&gt;).&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Whichever strategy you pick, the win is the same: your environment stops being a fragile, one-of-a-kind artifact and becomes something reproducible, reviewable, and one &lt;code&gt;git clone&lt;/code&gt; away. Start with the bare repo if you want to be versioned in five minutes; graduate to a modular repo with a bootstrap script when your config earns the structure. Either way, the next machine you sign in to will already feel like home.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.atlassian.com/git/tutorials/dotfiles&quot;&gt;The best way to store your dotfiles: A bare Git repository&lt;/a&gt; (Atlassian)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/MKAbuMattar/dotfiles&quot;&gt;MKAbuMattar/dotfiles the modular repo + bootstrap shown above&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/MKAbuMattar/skills&quot;&gt;MKAbuMattar/skills the linux- and python-script-developer skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=11070797&quot;&gt;Hacker News Discussion on Dotfiles Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://harfangk.github.io/2016/09/18/manage-dotfiles-with-a-git-bare-repository.html&quot;&gt;Managing Dotfiles With a Bare Git Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dotfiles.github.io/&quot;&gt;Dotfiles.github.io A guide to dotfiles on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.anishathalye.com/2014/08/03/managing-your-dotfiles/&quot;&gt;Using Git and GitHub to manage your dotfiles&lt;/a&gt; (Anish Athalye)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=2509090&quot;&gt;Ask HN: How do you manage your dotfiles?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://driesvints.com/blog/using-a-git-bare-repository-to-manage-your-dotfiles/&quot;&gt;Git Bare Repository A Better Way To Manage Dotfiles&lt;/a&gt; (Dries Vints)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Dotfiles&quot;&gt;ArchWiki: Dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/2021-02-10-github-does-dotfiles/&quot;&gt;GitHub Does Dotfiles&lt;/a&gt; (GitHub Blog)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/stow/&quot;&gt;GNU Stow for dotfiles management&lt;/a&gt; (Alternative approach)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.chezmoi.io/&quot;&gt;Chezmoi Manage your dotfiles across multiple diverse machines, securely&lt;/a&gt; (Popular dotfiles manager tool)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yadm.io/&quot;&gt;YADM Yet Another Dotfiles Manager&lt;/a&gt; (Another popular tool)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/&quot;&gt;Understanding Git --bare repositories&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/219977/what-is-a-bare-git-repository&quot;&gt;Stack Overflow: What is a bare git repository?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Linux</category><category>Git</category><category>Configuration Management</category><category>Developer Tools</category><category>Productivity</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0002-dotfiles/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Setting up Node JS, Express, MongoDB, Prettier, ESLint and Husky Application with Babel and authentication as an example</title><link>https://mkabumattar.com/blog/post/setting-up-node-js-express-mongodb-prettier-eslint-and-husky-application-with-babel-and-authentication-as-an-example/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/setting-up-node-js-express-mongodb-prettier-eslint-and-husky-application-with-babel-and-authentication-as-an-example/</guid><description>Setting up Node JS, Express, MongoDB, Prettier, ESLint and Husky Application with Babel and authentication as an example.</description><pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;All code from this tutorial as a complete package is available in this &lt;a href=&quot;https://github.com/MKAbuMattar/template-express&quot;&gt;repository&lt;/a&gt;. If you find this tutorial helpful, please share it with your friends and colleagues, and make sure to star the repository.&lt;/p&gt;
&lt;p&gt;Since the ECMAScript JavaScript Standard is revised annually, it is a good idea to update our code as well.&lt;/p&gt;
&lt;p&gt;The most recent JavaScript standards are occasionally incompatible with the browser. Something like to babel, which is nothing more than a JavaScript transpiler, is what we need to fix this sort of issue.&lt;/p&gt;
&lt;p&gt;So, in this little tutorial, I&amp;#39;ll explain how to set up babel for a basic NodeJS Express application so that we may utilize the most recent ES6 syntax in it then layer on MongoDB, a Winston logger, Prettier, ESLint, Husky git hooks, and JWT authentication.&lt;/p&gt;
&lt;Notice type=&quot;info&quot;&gt;
  By the end you&apos;ll have a production-ready Express API scaffold: ES module
  syntax via Babel, MongoDB through Mongoose, structured logging, enforced
  formatting and linting, git hooks that block bad commits, and a complete
  register/login flow secured with JSON Web Tokens.
&lt;/Notice&gt;&lt;p&gt;You&amp;#39;ll push the finished project to a remote over SSH, so if you haven&amp;#39;t set up your keys yet, see &lt;a href=&quot;/blog/post/git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux&quot;&gt;Git SSH Keys for GitHub, GitLab, and Bitbucket on Linux&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What is Babel?&lt;/h2&gt;
&lt;p&gt;Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments. Here are the main things Babel can do for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transform syntax&lt;/li&gt;
&lt;li&gt;Polyfill features that are missing in your target environment (through a third-party polyfill such as core-js)&lt;/li&gt;
&lt;li&gt;Source code transformations (codemods)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Project Setup&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll begin by creating a new directory called &lt;code&gt;backend-template&lt;/code&gt; and then we&amp;#39;ll create a new &lt;code&gt;package.json&lt;/code&gt; file. We&amp;#39;re going to be using pnpm for this example, but you could just as easily use npm or yarn if you prefer pnpm is fast and disk-efficient thanks to its content-addressable store.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mkdir backend-template
cd backend-template
pnpm init
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Engine Locking&lt;/h3&gt;
&lt;p&gt;The same Node engine and package management that we use should be available to all developers working on this project. We create two new files in order to achieve that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.nvmrc&lt;/code&gt;: Will disclose to other project users the Node version that is being utilized.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.npmrc&lt;/code&gt;: reveals to other project users the package manager being used.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .nvmrc
echo &amp;quot;lts/fermium&amp;quot; &amp;gt; .nvmrc
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .npmrc
echo &amp;#39;engine-strict=true\r\nsave-exact = true\r\ntag-version-prefix=&amp;quot;&amp;quot;\r\nstrict-peer-dependencies = false\r\nauto-install-peers = true\r\nlockfile = true&amp;#39; &amp;gt; .npmrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With pnpm, repo-wide install settings live in a &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt; file at the project root something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Only run install/build scripts for packages you trust to build native binaries.
onlyBuiltDependencies:
  - esbuild

# Pin a single resolution for a dependency across the whole tree.
overrides:
  # &amp;#39;some-transitive-pkg&amp;#39;: 1.2.3

# Optionally defer adopting brand-new releases (supply-chain safety).
# minimumReleaseAge: 1440
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notably, the usage of &lt;code&gt;engine-strict&lt;/code&gt; said nothing about &lt;code&gt;pnpm&lt;/code&gt; in particular; we handle that in &lt;code&gt;packages.json&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;open &lt;code&gt;packages.json&lt;/code&gt; add the &lt;code&gt;engines&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;tutorial&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;0.0.0&amp;quot;,
  &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,
  &amp;quot;keywords&amp;quot;: [],
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;author&amp;quot;: {
    &amp;quot;name&amp;quot;: &amp;quot;Mohammad Abu Mattar&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;mohammad.abumattar@outlook.com&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;https://mkabumattar.github.io/&amp;quot;
  },
  &amp;quot;homepage&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL#readme&amp;quot;,
  &amp;quot;repository&amp;quot;: {
    &amp;quot;type&amp;quot;: &amp;quot;git&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;git+YOUR_GIT_REPO_URL.git&amp;quot;
  },
  &amp;quot;bugs&amp;quot;: {
    &amp;quot;url&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL/issues&amp;quot;
  },
  &amp;quot;engines&amp;quot;: {
    &amp;quot;node&amp;quot;: &amp;quot;&amp;gt;=14.0.0&amp;quot;,
    &amp;quot;pnpm&amp;quot;: &amp;quot;&amp;gt;=8.0.0&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Babel Setup&lt;/h3&gt;
&lt;p&gt;For the production build we install two main Babel packages.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;code&gt;@babel/core&lt;/code&gt;&lt;/em&gt;: The primary package for running any Babel setup or configuration.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;code&gt;@babel/preset-env&lt;/code&gt;&lt;/em&gt;: Gives us access to modern JavaScript features and transpiles them down to a version the target Node.js understands.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Babel is mostly used in the code base to take advantage of new JavaScript capabilities. Unless the code is pure JavaScript, we don&amp;#39;t know if the server&amp;#39;s Node.js will comprehend the specific code or not so transpiling before deployment is advised, and that&amp;#39;s exactly what &lt;code&gt;@babel/cli&lt;/code&gt; does in the &lt;code&gt;build&lt;/code&gt; script.&lt;/p&gt;
&lt;Notice type=&quot;tip&quot;&gt;
  For development we don&apos;t want to transpile to disk on every save. Instead of
  `nodemon` + `babel-node`, we&apos;ll use [tsx](https://www.npmjs.com/package/tsx)
  a tiny Node.js runner powered by esbuild that executes modern ES module `.js`
  (and TypeScript) directly and ships a `--watch` mode, so it replaces **both**
  `nodemon` and `babel-node` with one dependency.
&lt;/Notice&gt;&lt;p&gt;Development Setup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add -D tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add express mongoose cors dotenv @babel/core @babel/preset-env

##  compression cookie-parser core-js crypto-js helmet jsonwebtoken lodash regenerator-runtime
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add -D @babel/cli babel-plugin-module-resolver
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we initialize the package.json and install the basic Express server, mongoose, cors, dotenv, &lt;code&gt;@babel/core&lt;/code&gt; and &lt;code&gt;@babel/preset-env&lt;/code&gt; (for the production build), plus the dev tooling: &lt;code&gt;tsx&lt;/code&gt;, &lt;code&gt;@babel/cli&lt;/code&gt;, and &lt;code&gt;babel-plugin-module-resolver&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Babel Configration&lt;/h4&gt;
&lt;p&gt;After that, we need to create a file called &lt;code&gt;.babelrc&lt;/code&gt; in the project&amp;#39;s root directory, and we paste the following block of code there.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .babelrc
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;presets&amp;quot;: [&amp;quot;@babel/preset-env&amp;quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Code Formatting and Quality Tools&lt;/h3&gt;
&lt;p&gt;We will be using two tools in order to establish a standard that will be utilized by all project participants to maintain consistency in the coding style and the use of fundamental best practices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/&quot;&gt;Prettier&lt;/a&gt;: A tool that will help us to format our code consistently.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint&lt;/a&gt;: A tool that will help us to enforce a consistent coding style.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Prettier&lt;/h4&gt;
&lt;p&gt;Prettier will handle the automated file formatting for us. Add it to the project right now.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s only needed during development, so I&amp;#39;ll add it as a &lt;code&gt;devDependency&lt;/code&gt; with &lt;code&gt;-D&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add -D prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;Notice type=&quot;tip&quot;&gt;
  Install the [Prettier VS Code
  extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
  so the editor formats on save instead of you running the CLI by hand. Keep
  Prettier in the project&apos;s dependencies anyway VS Code uses your project&apos;s
  local config and version.
&lt;/Notice&gt;&lt;p&gt;We&amp;#39;ll create two files in the root:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.prettierrc&lt;/code&gt;: This file will contain the configuration for prettier.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.prettierignore&lt;/code&gt;: This file will contain the list of files that should be ignored by prettier.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;trailingComma&amp;quot;: &amp;quot;all&amp;quot;,
  &amp;quot;printWidth&amp;quot;: 80,
  &amp;quot;tabWidth&amp;quot;: 2,
  &amp;quot;useTabs&amp;quot;: false,
  &amp;quot;semi&amp;quot;: false,
  &amp;quot;singleQuote&amp;quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;node_modules
build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;#39;ve listed the folders in that file that I don&amp;#39;t want Prettier to waste any time working on. If you&amp;#39;d want to disregard specific file types in groups, you may also use patterns like *.html.&lt;/p&gt;
&lt;p&gt;Now we add a new script to &lt;code&gt;package.json&lt;/code&gt; so we can run Prettier:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;tutorial&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;0.0.0&amp;quot;,
  &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,
  &amp;quot;keywords&amp;quot;: [],
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;node build/bin/www.js&amp;quot;,
    &amp;quot;dev&amp;quot;: &amp;quot;tsx watch src/bin/www.js&amp;quot;,
    &amp;quot;clean&amp;quot;: &amp;quot;rm -rf build&amp;quot;,
    &amp;quot;build&amp;quot;: &amp;quot;pnpm clean &amp;amp;&amp;amp; pnpm exec babel src -d build --minified --presets @babel/preset-env&amp;quot;,
    &amp;quot;lint&amp;quot;: &amp;quot;eslint \&amp;quot;src/**/*.js\&amp;quot; --fix&amp;quot;,
    &amp;quot;lint:check&amp;quot;: &amp;quot;eslint \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prettier&amp;quot;: &amp;quot;prettier --write \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prettier:check&amp;quot;: &amp;quot;prettier --check \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prepare&amp;quot;: &amp;quot;husky install&amp;quot;
  },
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;author&amp;quot;: {
    &amp;quot;name&amp;quot;: &amp;quot;YOUR_NAME&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;YOUR_EMAIL&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;YOUR_WEBSITE&amp;quot;
  },
  &amp;quot;homepage&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL#readme&amp;quot;,
  &amp;quot;repository&amp;quot;: {
    &amp;quot;type&amp;quot;: &amp;quot;git&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;git+YOUR_GIT_REPO_URL.git&amp;quot;
  },
  &amp;quot;bugs&amp;quot;: {
    &amp;quot;url&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL/issues&amp;quot;
  },
  &amp;quot;engines&amp;quot;: {
    &amp;quot;node&amp;quot;: &amp;quot;&amp;gt;=14.0.0&amp;quot;,
    &amp;quot;pnpm&amp;quot;: &amp;quot;&amp;gt;=8.0.0&amp;quot;
  },
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;@babel/core&amp;quot;: &amp;quot;7.18.5&amp;quot;,
    &amp;quot;@babel/preset-env&amp;quot;: &amp;quot;7.18.2&amp;quot;,
    &amp;quot;compression&amp;quot;: &amp;quot;1.7.4&amp;quot;,
    &amp;quot;cookie-parser&amp;quot;: &amp;quot;1.4.6&amp;quot;,
    &amp;quot;core-js&amp;quot;: &amp;quot;3.23.2&amp;quot;,
    &amp;quot;cors&amp;quot;: &amp;quot;2.8.5&amp;quot;,
    &amp;quot;crypto-js&amp;quot;: &amp;quot;4.1.1&amp;quot;,
    &amp;quot;dotenv&amp;quot;: &amp;quot;16.0.1&amp;quot;,
    &amp;quot;express&amp;quot;: &amp;quot;4.18.1&amp;quot;,
    &amp;quot;helmet&amp;quot;: &amp;quot;5.1.0&amp;quot;,
    &amp;quot;husky&amp;quot;: &amp;quot;8.0.1&amp;quot;,
    &amp;quot;jsonwebtoken&amp;quot;: &amp;quot;9.0.0&amp;quot;,
    &amp;quot;mongoose&amp;quot;: &amp;quot;6.11.3&amp;quot;,
    &amp;quot;regenerator-runtime&amp;quot;: &amp;quot;0.13.9&amp;quot;,
    &amp;quot;winston&amp;quot;: &amp;quot;3.8.0&amp;quot;
  },
  &amp;quot;devDependencies&amp;quot;: {
    &amp;quot;@babel/cli&amp;quot;: &amp;quot;7.17.10&amp;quot;,
    &amp;quot;@commitlint/cli&amp;quot;: &amp;quot;17.0.3&amp;quot;,
    &amp;quot;@commitlint/config-conventional&amp;quot;: &amp;quot;17.0.3&amp;quot;,
    &amp;quot;babel-plugin-module-resolver&amp;quot;: &amp;quot;4.1.0&amp;quot;,
    &amp;quot;eslint&amp;quot;: &amp;quot;8.18.0&amp;quot;,
    &amp;quot;eslint-config-airbnb-base&amp;quot;: &amp;quot;15.0.0&amp;quot;,
    &amp;quot;eslint-config-prettier&amp;quot;: &amp;quot;8.5.0&amp;quot;,
    &amp;quot;eslint-plugin-import&amp;quot;: &amp;quot;2.26.0&amp;quot;,
    &amp;quot;eslint-plugin-prettier&amp;quot;: &amp;quot;4.0.0&amp;quot;,
    &amp;quot;prettier&amp;quot;: &amp;quot;2.7.1&amp;quot;,
    &amp;quot;tsx&amp;quot;: &amp;quot;4.19.2&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now run &lt;code&gt;pnpm prettier&lt;/code&gt; to format all files in the project, or &lt;code&gt;pnpm prettier:check&lt;/code&gt; to check if all files are formatted correctly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm prettier:check
pnpm prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to automatically format, repair, and save all files in your project that you haven&amp;#39;t ignored. My formatter updated around 7 files by default. The source control tab on the left of VS Code has a list of altered files where you may find them.&lt;/p&gt;
&lt;h4&gt;ESLint&lt;/h4&gt;
&lt;p&gt;We&amp;#39;ll begin with ESLint, which is a tool that will help us to enforce a consistent coding style, at first need to install the dependencies.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add -D eslint eslint-config-airbnb-base eslint-config-prettier eslint-plugin-import eslint-plugin-prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll create two files in the root:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.eslintrc&lt;/code&gt;: This file will contain the configuration for ESLint.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.eslintignore&lt;/code&gt;: This file will contain the list of files that should be ignored by ESLint.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;extends&amp;quot;: [
    &amp;quot;airbnb-base&amp;quot;,
    &amp;quot;plugin:prettier/recommended&amp;quot;,
    &amp;quot;plugin:import/errors&amp;quot;,
    &amp;quot;plugin:import/warnings&amp;quot;
  ],
  &amp;quot;plugins&amp;quot;: [&amp;quot;prettier&amp;quot;],
  &amp;quot;rules&amp;quot;: {
    &amp;quot;prettier/prettier&amp;quot;: &amp;quot;error&amp;quot;,
    &amp;quot;import/no-named-as-default&amp;quot;: &amp;quot;off&amp;quot;,
    &amp;quot;no-underscore-dangle&amp;quot;: &amp;quot;off&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;node_modules
build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we add a new script to &lt;code&gt;package.json&lt;/code&gt; so we can run ESLint:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;tutorial&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;0.0.0&amp;quot;,
  &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,
  &amp;quot;keywords&amp;quot;: [],
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;node build/bin/www.js&amp;quot;,
    &amp;quot;dev&amp;quot;: &amp;quot;tsx watch src/bin/www.js&amp;quot;,
    &amp;quot;clean&amp;quot;: &amp;quot;rm -rf build&amp;quot;,
    &amp;quot;build&amp;quot;: &amp;quot;pnpm clean &amp;amp;&amp;amp; pnpm exec babel src -d build --minified --presets @babel/preset-env&amp;quot;,
    &amp;quot;lint&amp;quot;: &amp;quot;eslint \&amp;quot;src/**/*.js\&amp;quot; --fix&amp;quot;,
    &amp;quot;lint:check&amp;quot;: &amp;quot;eslint \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prettier&amp;quot;: &amp;quot;prettier --write \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prettier:check&amp;quot;: &amp;quot;prettier --check \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prepare&amp;quot;: &amp;quot;husky install&amp;quot;
  },
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;author&amp;quot;: {
    &amp;quot;name&amp;quot;: &amp;quot;YOUR_NAME&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;YOUR_EMAIL&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;YOUR_WEBSITE&amp;quot;
  },
  &amp;quot;homepage&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL#readme&amp;quot;,
  &amp;quot;repository&amp;quot;: {
    &amp;quot;type&amp;quot;: &amp;quot;git&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;git+YOUR_GIT_REPO_URL.git&amp;quot;
  },
  &amp;quot;bugs&amp;quot;: {
    &amp;quot;url&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL/issues&amp;quot;
  },
  &amp;quot;engines&amp;quot;: {
    &amp;quot;node&amp;quot;: &amp;quot;&amp;gt;=14.0.0&amp;quot;,
    &amp;quot;pnpm&amp;quot;: &amp;quot;&amp;gt;=8.0.0&amp;quot;
  },
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;@babel/core&amp;quot;: &amp;quot;7.18.5&amp;quot;,
    &amp;quot;@babel/preset-env&amp;quot;: &amp;quot;7.18.2&amp;quot;,
    &amp;quot;compression&amp;quot;: &amp;quot;1.7.4&amp;quot;,
    &amp;quot;cookie-parser&amp;quot;: &amp;quot;1.4.6&amp;quot;,
    &amp;quot;core-js&amp;quot;: &amp;quot;3.23.2&amp;quot;,
    &amp;quot;cors&amp;quot;: &amp;quot;2.8.5&amp;quot;,
    &amp;quot;crypto-js&amp;quot;: &amp;quot;4.1.1&amp;quot;,
    &amp;quot;dotenv&amp;quot;: &amp;quot;16.0.1&amp;quot;,
    &amp;quot;express&amp;quot;: &amp;quot;4.18.1&amp;quot;,
    &amp;quot;helmet&amp;quot;: &amp;quot;5.1.0&amp;quot;,
    &amp;quot;husky&amp;quot;: &amp;quot;8.0.1&amp;quot;,
    &amp;quot;jsonwebtoken&amp;quot;: &amp;quot;9.0.0&amp;quot;,
    &amp;quot;mongoose&amp;quot;: &amp;quot;6.11.3&amp;quot;,
    &amp;quot;regenerator-runtime&amp;quot;: &amp;quot;0.13.9&amp;quot;,
    &amp;quot;winston&amp;quot;: &amp;quot;3.8.0&amp;quot;
  },
  &amp;quot;devDependencies&amp;quot;: {
    &amp;quot;@babel/cli&amp;quot;: &amp;quot;7.17.10&amp;quot;,
    &amp;quot;@commitlint/cli&amp;quot;: &amp;quot;17.0.3&amp;quot;,
    &amp;quot;@commitlint/config-conventional&amp;quot;: &amp;quot;17.0.3&amp;quot;,
    &amp;quot;babel-plugin-module-resolver&amp;quot;: &amp;quot;4.1.0&amp;quot;,
    &amp;quot;eslint&amp;quot;: &amp;quot;8.18.0&amp;quot;,
    &amp;quot;eslint-config-airbnb-base&amp;quot;: &amp;quot;15.0.0&amp;quot;,
    &amp;quot;eslint-config-prettier&amp;quot;: &amp;quot;8.5.0&amp;quot;,
    &amp;quot;eslint-plugin-import&amp;quot;: &amp;quot;2.26.0&amp;quot;,
    &amp;quot;eslint-plugin-prettier&amp;quot;: &amp;quot;4.0.0&amp;quot;,
    &amp;quot;prettier&amp;quot;: &amp;quot;2.7.1&amp;quot;,
    &amp;quot;tsx&amp;quot;: &amp;quot;4.19.2&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can test out your config by running:&lt;/p&gt;
&lt;p&gt;You can now run &lt;code&gt;pnpm lint&lt;/code&gt; to format all files in the project, or &lt;code&gt;pnpm lint:check&lt;/code&gt; to check if all files are formatted correctly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm lint:check
pnpm lint
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Setup logger for development&lt;/h3&gt;
&lt;p&gt;I had a problem setting up the logger when constructing a server-side application based on Node and Express router. Conditions for the answer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Logging application event&lt;/li&gt;
&lt;li&gt;Ability to specify multiple logs level&lt;/li&gt;
&lt;li&gt;Logging of HTTP requests&lt;/li&gt;
&lt;li&gt;Ability to write logs into a different source (console and file)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I found two possible solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/morgan&quot;&gt;Morgan&lt;/a&gt;: HTTP logging middleware for express. It provides the ability to log incoming requests by specifying the formatting of log instance based on different request related information.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/winston&quot;&gt;Winston&lt;/a&gt;: Multiple types of transports are supported by a lightweight yet effective logging library. Because I want to simultaneously log events into a file and a terminal, this practical feature is crucial for me.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#39;ll use Winston for the logging, first I&amp;#39;ll install the package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add winston
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I&amp;#39;ll create a file called &lt;code&gt;utils/logger.util.js&lt;/code&gt; in it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch src/utils/logger.util.js
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import {NODE_ENV} from &amp;#39;../env/variable.env&amp;#39;;
import winston from &amp;#39;winston&amp;#39;;

const levels = {
  error: 0,
  warn: 1,
  info: 2,
  http: 3,
  debug: 4,
};

const level = () =&amp;gt; {
  const env = NODE_ENV || &amp;#39;development&amp;#39;;
  const isDevelopment = env === &amp;#39;development&amp;#39;;
  return isDevelopment ? &amp;#39;debug&amp;#39; : &amp;#39;warn&amp;#39;;
};

const colors = {
  error: &amp;#39;red&amp;#39;,
  warn: &amp;#39;yellow&amp;#39;,
  info: &amp;#39;green&amp;#39;,
  http: &amp;#39;magenta&amp;#39;,
  debug: &amp;#39;white&amp;#39;,
};

winston.addColors(colors);

const format = winston.format.combine(
  winston.format.timestamp({
    format: &amp;#39;YYYY-MM-DD HH:mm:ss:ms&amp;#39;,
  }),
  winston.format.colorize({all: true}),
  winston.format.printf(
    (info) =&amp;gt; `${info.timestamp} ${info.level}: ${info.message}`,
  ),
);

const transports = [
  new winston.transports.Console(),
  new winston.transports.File({
    filename: &amp;#39;logs/error.log&amp;#39;,
    level: &amp;#39;error&amp;#39;,
  }),
  new winston.transports.File({filename: &amp;#39;logs/all.log&amp;#39;}),
];

const logger = winston.createLogger({
  level: level(),
  levels,
  format,
  transports,
});

export default logger;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Build file structure and basic express application&lt;/h3&gt;
&lt;p&gt;at first we&amp;#39;ll create a directory called &lt;code&gt;src&lt;/code&gt;, and we&amp;#39;ll build the file structure inside of it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mkdir src
cd src

mkdir bin config constants controllers env middlewares models repositories routers schemas security services validations
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the directory layout we&amp;#39;re building inside &lt;code&gt;src&lt;/code&gt;:&lt;/p&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;src/&lt;ul&gt;
&lt;li&gt;bin/ server bootstrap (&lt;a href=&quot;http://www.js&quot;&gt;www.js&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;config/ database connection&lt;/li&gt;
&lt;li&gt;constants/ shared constants (HTTP codes, messages, paths)&lt;/li&gt;
&lt;li&gt;controllers/ request handlers&lt;/li&gt;
&lt;li&gt;env/ environment-variable loading&lt;/li&gt;
&lt;li&gt;middlewares/ auth and error middleware&lt;/li&gt;
&lt;li&gt;models/ Mongoose models&lt;/li&gt;
&lt;li&gt;repositories/ data-access layer&lt;/li&gt;
&lt;li&gt;routers/ route definitions&lt;/li&gt;
&lt;li&gt;schemas/ Mongoose schemas&lt;/li&gt;
&lt;li&gt;security/ hashing and token helpers&lt;/li&gt;
&lt;li&gt;services/ business logic&lt;/li&gt;
&lt;li&gt;validations/ request validation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;p&gt;for robust and don&amp;#39;t repeat some text we&amp;#39;ll create constants files in the &lt;code&gt;constants&lt;/code&gt; directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch src/constants/api.constant.js src/constants/dateformat.constant.js src/constants/http.code.constant.js src/constants/http.reason.constant.js src/constants/message.constant.js src/constants/model.constant.js src/constants/number.constant.js src/constants/path.constant.js src/constants/regex.constant.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;there are some constants that are used in the application, but that are not related to the application itself. For example, the constants that are used in the API are in the &lt;code&gt;api.constant.js&lt;/code&gt; file, and there is a file that provides freely for HTTP codes and replies, but we&amp;#39;ll make one from start.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const YYYY_MM_DD_HH_MM_SS_MS = &amp;#39;YYYY-MM-DD HH:mm:ss:ms&amp;#39;;

export default {
  YYYY_MM_DD_HH_MM_SS_MS,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const CONTINUE = 100;
export const SWITCHING_PROTOCOLS = 101;
export const PROCESSING = 102;
export const OK = 200;
export const CREATED = 201;
export const ACCEPTED = 202;
export const NON_AUTHORITATIVE_INFORMATION = 203;
export const NO_CONTENT = 204;
export const RESET_CONTENT = 205;
export const PARTIAL_CONTENT = 206;
export const MULTI_STATUS = 207;
export const ALREADY_REPORTED = 208;
export const IM_USED = 226;
export const MULTIPLE_CHOICES = 300;
export const MOVED_PERMANENTLY = 301;
export const MOVED_TEMPORARILY = 302;
export const SEE_OTHER = 303;
export const NOT_MODIFIED = 304;
export const USE_PROXY = 305;
export const SWITCH_PROXY = 306;
export const TEMPORARY_REDIRECT = 307;
export const BAD_REQUEST = 400;
export const UNAUTHORIZED = 401;
export const PAYMENT_REQUIRED = 402;
export const FORBIDDEN = 403;
export const NOT_FOUND = 404;
export const METHOD_NOT_ALLOWED = 405;
export const NOT_ACCEPTABLE = 406;
export const PROXY_AUTHENTICATION_REQUIRED = 407;
export const REQUEST_TIMEOUT = 408;
export const CONFLICT = 409;
export const GONE = 410;
export const LENGTH_REQUIRED = 411;
export const PRECONDITION_FAILED = 412;
export const PAYLOAD_TOO_LARGE = 413;
export const REQUEST_URI_TOO_LONG = 414;
export const UNSUPPORTED_MEDIA_TYPE = 415;
export const REQUESTED_RANGE_NOT_SATISFIABLE = 416;
export const EXPECTATION_FAILED = 417;
export const IM_A_TEAPOT = 418;
export const METHOD_FAILURE = 420;
export const MISDIRECTED_REQUEST = 421;
export const UNPROCESSABLE_ENTITY = 422;
export const LOCKED = 423;
export const FAILED_DEPENDENCY = 424;
export const UPGRADE_REQUIRED = 426;
export const PRECONDITION_REQUIRED = 428;
export const TOO_MANY_REQUESTS = 429;
export const REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
export const UNAVAILABLE_FOR_LEGAL_REASONS = 451;
export const INTERNAL_SERVER_ERROR = 500;
export const NOT_IMPLEMENTED = 501;
export const BAD_GATEWAY = 502;
export const SERVICE_UNAVAILABLE = 503;
export const GATEWAY_TIMEOUT = 504;
export const HTTP_VERSION_NOT_SUPPORTED = 505;
export const VARIANT_ALSO_NEGOTIATES = 506;
export const INSUFFICIENT_STORAGE = 507;
export const LOOP_DETECTED = 508;
export const NOT_EXTENDED = 510;
export const NETWORK_AUTHENTICATION_REQUIRED = 511;
export const NETWORK_CONNECT_TIMEOUT_ERROR = 599;

export default {
  CONTINUE,
  SWITCHING_PROTOCOLS,
  PROCESSING,
  OK,
  CREATED,
  ACCEPTED,
  NON_AUTHORITATIVE_INFORMATION,
  NO_CONTENT,
  RESET_CONTENT,
  PARTIAL_CONTENT,
  MULTI_STATUS,
  ALREADY_REPORTED,
  IM_USED,
  MULTIPLE_CHOICES,
  MOVED_PERMANENTLY,
  MOVED_TEMPORARILY,
  SEE_OTHER,
  NOT_MODIFIED,
  USE_PROXY,
  SWITCH_PROXY,
  TEMPORARY_REDIRECT,
  BAD_REQUEST,
  UNAUTHORIZED,
  PAYMENT_REQUIRED,
  FORBIDDEN,
  NOT_FOUND,
  METHOD_NOT_ALLOWED,
  NOT_ACCEPTABLE,
  PROXY_AUTHENTICATION_REQUIRED,
  REQUEST_TIMEOUT,
  CONFLICT,
  GONE,
  LENGTH_REQUIRED,
  PRECONDITION_FAILED,
  PAYLOAD_TOO_LARGE,
  REQUEST_URI_TOO_LONG,
  UNSUPPORTED_MEDIA_TYPE,
  REQUESTED_RANGE_NOT_SATISFIABLE,
  EXPECTATION_FAILED,
  IM_A_TEAPOT,
  METHOD_FAILURE,
  MISDIRECTED_REQUEST,
  UNPROCESSABLE_ENTITY,
  LOCKED,
  FAILED_DEPENDENCY,
  UPGRADE_REQUIRED,
  PRECONDITION_REQUIRED,
  TOO_MANY_REQUESTS,
  REQUEST_HEADER_FIELDS_TOO_LARGE,
  UNAVAILABLE_FOR_LEGAL_REASONS,
  INTERNAL_SERVER_ERROR,
  NOT_IMPLEMENTED,
  BAD_GATEWAY,
  SERVICE_UNAVAILABLE,
  GATEWAY_TIMEOUT,
  HTTP_VERSION_NOT_SUPPORTED,
  VARIANT_ALSO_NEGOTIATES,
  INSUFFICIENT_STORAGE,
  LOOP_DETECTED,
  NOT_EXTENDED,
  NETWORK_AUTHENTICATION_REQUIRED,
  NETWORK_CONNECT_TIMEOUT_ERROR,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const CONTINUE = &amp;#39;Continue&amp;#39;;
export const SWITCHING_PROTOCOLS = &amp;#39;Switching Protocols&amp;#39;;
export const PROCESSING = &amp;#39;Processing&amp;#39;;
export const OK = &amp;#39;OK&amp;#39;;
export const CREATED = &amp;#39;Created&amp;#39;;
export const ACCEPTED = &amp;#39;Accepted&amp;#39;;
export const NON_AUTHORITATIVE_INFORMATION = &amp;#39;Non-Authoritative Information&amp;#39;;
export const NO_CONTENT = &amp;#39;No Content&amp;#39;;
export const RESET_CONTENT = &amp;#39;Reset Content&amp;#39;;
export const PARTIAL_CONTENT = &amp;#39;Partial Content&amp;#39;;
export const MULTI_STATUS = &amp;#39;Multi-Status&amp;#39;;
export const ALREADY_REPORTED = &amp;#39;Already Reported&amp;#39;;
export const IM_USED = &amp;#39;IM Used&amp;#39;;
export const MULTIPLE_CHOICES = &amp;#39;Multiple Choices&amp;#39;;
export const MOVED_PERMANENTLY = &amp;#39;Moved Permanently&amp;#39;;
export const MOVED_TEMPORARILY = &amp;#39;Moved Temporarily&amp;#39;;
export const SEE_OTHER = &amp;#39;See Other&amp;#39;;
export const NOT_MODIFIED = &amp;#39;Not Modified&amp;#39;;
export const USE_PROXY = &amp;#39;Use Proxy&amp;#39;;
export const SWITCH_PROXY = &amp;#39;Switch Proxy&amp;#39;;
export const TEMPORARY_REDIRECT = &amp;#39;Temporary Redirect&amp;#39;;
export const BAD_REQUEST = &amp;#39;Bad Request&amp;#39;;
export const UNAUTHORIZED = &amp;#39;Unauthorized&amp;#39;;
export const PAYMENT_REQUIRED = &amp;#39;Payment Required&amp;#39;;
export const FORBIDDEN = &amp;#39;Forbidden&amp;#39;;
export const NOT_FOUND = &amp;#39;Not Found&amp;#39;;
export const METHOD_NOT_ALLOWED = &amp;#39;Method Not Allowed&amp;#39;;
export const NOT_ACCEPTABLE = &amp;#39;Not Acceptable&amp;#39;;
export const PROXY_AUTHENTICATION_REQUIRED = &amp;#39;Proxy Authentication Required&amp;#39;;
export const REQUEST_TIMEOUT = &amp;#39;Request Timeout&amp;#39;;
export const CONFLICT = &amp;#39;Conflict&amp;#39;;
export const GONE = &amp;#39;Gone&amp;#39;;
export const LENGTH_REQUIRED = &amp;#39;Length Required&amp;#39;;
export const PRECONDITION_FAILED = &amp;#39;Precondition Failed&amp;#39;;
export const PAYLOAD_TOO_LARGE = &amp;#39;Payload Too Large&amp;#39;;
export const REQUEST_URI_TOO_LONG = &amp;#39;Request URI Too Long&amp;#39;;
export const UNSUPPORTED_MEDIA_TYPE = &amp;#39;Unsupported Media Type&amp;#39;;
export const REQUESTED_RANGE_NOT_SATISFIABLE =
  &amp;#39;Requested Range Not Satisfiable&amp;#39;;
export const EXPECTATION_FAILED = &amp;#39;Expectation Failed&amp;#39;;
export const IM_A_TEAPOT = &amp;quot;I&amp;#39;m a teapot&amp;quot;;
export const METHOD_FAILURE = &amp;#39;Method Failure&amp;#39;;
export const MISDIRECTED_REQUEST = &amp;#39;Misdirected Request&amp;#39;;
export const UNPROCESSABLE_ENTITY = &amp;#39;Unprocessable Entity&amp;#39;;
export const LOCKED = &amp;#39;Locked&amp;#39;;
export const FAILED_DEPENDENCY = &amp;#39;Failed Dependency&amp;#39;;
export const UPGRADE_REQUIRED = &amp;#39;Upgrade Required&amp;#39;;
export const PRECONDITION_REQUIRED = &amp;#39;Precondition Required&amp;#39;;
export const TOO_MANY_REQUESTS = &amp;#39;Too Many Requests&amp;#39;;
export const REQUEST_HEADER_FIELDS_TOO_LARGE =
  &amp;#39;Request Header Fields Too Large&amp;#39;;
export const UNAVAILABLE_FOR_LEGAL_REASONS = &amp;#39;Unavailable For Legal Reasons&amp;#39;;
export const INTERNAL_SERVER_ERROR = &amp;#39;Internal Server Error&amp;#39;;
export const NOT_IMPLEMENTED = &amp;#39;Not Implemented&amp;#39;;
export const BAD_GATEWAY = &amp;#39;Bad Gateway&amp;#39;;
export const SERVICE_UNAVAILABLE = &amp;#39;Service Unavailable&amp;#39;;
export const GATEWAY_TIMEOUT = &amp;#39;Gateway Timeout&amp;#39;;
export const HTTP_VERSION_NOT_SUPPORTED = &amp;#39;HTTP Version Not Supported&amp;#39;;
export const VARIANT_ALSO_NEGOTIATES = &amp;#39;Variant Also Negotiates&amp;#39;;
export const INSUFFICIENT_STORAGE = &amp;#39;Insufficient Storage&amp;#39;;
export const LOOP_DETECTED = &amp;#39;Loop Detected&amp;#39;;
export const NOT_EXTENDED = &amp;#39;Not Extended&amp;#39;;
export const NETWORK_AUTHENTICATION_REQUIRED =
  &amp;#39;Network Authentication Required&amp;#39;;
export const NETWORK_CONNECT_TIMEOUT_ERROR = &amp;#39;Network Connect Timeout Error&amp;#39;;

export default {
  CONTINUE,
  SWITCHING_PROTOCOLS,
  PROCESSING,
  OK,
  CREATED,
  ACCEPTED,
  NON_AUTHORITATIVE_INFORMATION,
  NO_CONTENT,
  RESET_CONTENT,
  PARTIAL_CONTENT,
  MULTI_STATUS,
  ALREADY_REPORTED,
  IM_USED,
  MULTIPLE_CHOICES,
  MOVED_PERMANENTLY,
  MOVED_TEMPORARILY,
  SEE_OTHER,
  NOT_MODIFIED,
  USE_PROXY,
  SWITCH_PROXY,
  TEMPORARY_REDIRECT,
  BAD_REQUEST,
  UNAUTHORIZED,
  PAYMENT_REQUIRED,
  FORBIDDEN,
  NOT_FOUND,
  METHOD_NOT_ALLOWED,
  NOT_ACCEPTABLE,
  PROXY_AUTHENTICATION_REQUIRED,
  REQUEST_TIMEOUT,
  CONFLICT,
  GONE,
  LENGTH_REQUIRED,
  PRECONDITION_FAILED,
  PAYLOAD_TOO_LARGE,
  REQUEST_URI_TOO_LONG,
  UNSUPPORTED_MEDIA_TYPE,
  REQUESTED_RANGE_NOT_SATISFIABLE,
  EXPECTATION_FAILED,
  IM_A_TEAPOT,
  METHOD_FAILURE,
  MISDIRECTED_REQUEST,
  UNPROCESSABLE_ENTITY,
  LOCKED,
  FAILED_DEPENDENCY,
  UPGRADE_REQUIRED,
  PRECONDITION_REQUIRED,
  TOO_MANY_REQUESTS,
  REQUEST_HEADER_FIELDS_TOO_LARGE,
  UNAVAILABLE_FOR_LEGAL_REASONS,
  INTERNAL_SERVER_ERROR,
  NOT_IMPLEMENTED,
  BAD_GATEWAY,
  SERVICE_UNAVAILABLE,
  GATEWAY_TIMEOUT,
  HTTP_VERSION_NOT_SUPPORTED,
  VARIANT_ALSO_NEGOTIATES,
  INSUFFICIENT_STORAGE,
  LOOP_DETECTED,
  NOT_EXTENDED,
  NETWORK_AUTHENTICATION_REQUIRED,
  NETWORK_CONNECT_TIMEOUT_ERROR,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const LOGS_ALL = &amp;#39;logs/all.log&amp;#39;;
export const LOGS_ERROR = &amp;#39;logs/error.log&amp;#39;;

export default {
  LOGS_ALL,
  LOGS_ERROR,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we&amp;#39;ll add to other constants in the future.&lt;/p&gt;
&lt;p&gt;after creating the directory structure, we&amp;#39;ll create a file called &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;.env.example&lt;/code&gt; in the root directory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.env&lt;/code&gt;: This file will contain the configuration for the application.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env.example&lt;/code&gt;: is the file that contains all of the configurations for constants that &lt;code&gt;.env&lt;/code&gt; has, but without values; only this one is versioned. &lt;code&gt;env.example&lt;/code&gt; serves as a template for building a &lt;code&gt;.env&lt;/code&gt; file that contains the information required to start the program.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cd ..

touch .env .env.example
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we add a new variable to &lt;code&gt;.env&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;NODE_ENV=development
# NODE_ENV=production
PORT=3030
DATABASE_URL=mongodb://127.0.0.1:27017/example
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;NODE_ENV=development
# NODE_ENV=production
PORT=3030
DATABASE_URL=mongodb://
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;after creating the directory structure and &lt;code&gt;.env&lt;/code&gt; files, we&amp;#39;ll create a file called &lt;code&gt;index.js&lt;/code&gt;, &lt;code&gt;bin/www.js&lt;/code&gt;, &lt;code&gt;config/db.config.js&lt;/code&gt; and &lt;code&gt;env/variable.env.js&lt;/code&gt; in the &lt;code&gt;src&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch src/index.js src/bin/www.js src/config/db.config.js src/env/variable.env.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;new files will be created in the &lt;code&gt;src&lt;/code&gt; directory, and we&amp;#39;ll add the following code to each of them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import logger from &amp;#39;../utils/logger.util&amp;#39;;
import {connect} from &amp;#39;mongoose&amp;#39;;

const connectDb = async (URL) =&amp;gt; {
  const connectionParams = {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  };

  try {
    const connection = await connect(URL, connectionParams);
    logger.info(`Mongo DB is connected to: ${connection.connection.host}`);
  } catch (err) {
    logger.error(`An error ocurred\n\r\n\r${err}`);
  }
};

export default connectDb;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import dotenv from &amp;#39;dotenv&amp;#39;;

dotenv.config();

export const {NODE_ENV} = process.env;
export const {PORT} = process.env;
export const {DATABASE_URL} = process.env;

export default {
  NODE_ENV,
  PORT,
  DATABASE_URL,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import connectDb from &amp;#39;./config/db.config&amp;#39;;
//http constant
import ConstantHttpCode from &amp;#39;./constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;./constants/http.reason.constant&amp;#39;;
import {DATABASE_URL} from &amp;#39;./env/variable.env&amp;#39;;
import cors from &amp;#39;cors&amp;#39;;
import express from &amp;#39;express&amp;#39;;

connectDb(DATABASE_URL);

const app = express();

app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(cors());

app.get(&amp;#39;/&amp;#39;, (req, res, next) =&amp;gt; {
  try {
    res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      API: &amp;#39;Work&amp;#39;,
    });
  } catch (err) {
    next(err);
  }
});

export default app;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;#!/user/bin/env node
import app from &amp;#39;..&amp;#39;;
import {PORT} from &amp;#39;../env/variable.env&amp;#39;;
import logger from &amp;#39;../utils/logger.util&amp;#39;;
import http from &amp;#39;http&amp;#39;;

/**
 * Normalize a port into a number, string, or false.
 */
const normalizePort = (val) =&amp;gt; {
  const port = parseInt(val, 10);

  if (Number.isNaN(port)) {
    // named pipe
    return val;
  }

  if (port &amp;gt;= 0) {
    // port number
    return port;
  }

  return false;
};

const port = normalizePort(PORT || &amp;#39;3000&amp;#39;);
app.set(&amp;#39;port&amp;#39;, port);

/**
 * Create HTTP server.
 */
const server = http.createServer(app);

/**
 * Event listener for HTTP server &amp;quot;error&amp;quot; event.
 */
const onError = (error) =&amp;gt; {
  if (error.syscall !== &amp;#39;listen&amp;#39;) {
    throw error;
  }

  const bind = typeof port === &amp;#39;string&amp;#39; ? `Pipe ${port}` : `Port ${port}`;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case &amp;#39;EACCES&amp;#39;:
      logger.error(`${bind} requires elevated privileges`);
      process.exit(1);
      break;
    case &amp;#39;EADDRINUSE&amp;#39;:
      logger.error(`${bind} is already in use`);
      process.exit(1);
      break;
    default:
      throw error;
  }
};

/**
 * Event listener for HTTP server &amp;quot;listening&amp;quot; event.
 */
const onListening = () =&amp;gt; {
  const addr = server.address();
  const bind = typeof addr === &amp;#39;string&amp;#39; ? `pipe ${addr}` : `port ${addr.port}`;
  logger.info(`Listening on ${bind}`);
};

server.listen(port);
server.on(&amp;#39;error&amp;#39;, onError);
server.on(&amp;#39;listening&amp;#39;, onListening);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we add a new script to &lt;code&gt;package.json&lt;/code&gt; so we can run the application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;tutorial&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;0.0.0&amp;quot;,
  &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,
  &amp;quot;keywords&amp;quot;: [],
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;node build/bin/www.js&amp;quot;,
    &amp;quot;dev&amp;quot;: &amp;quot;tsx watch src/bin/www.js&amp;quot;,
    &amp;quot;clean&amp;quot;: &amp;quot;rm -rf build&amp;quot;,
    &amp;quot;build&amp;quot;: &amp;quot;pnpm clean &amp;amp;&amp;amp; pnpm exec babel src -d build --minified --presets @babel/preset-env&amp;quot;,
    &amp;quot;lint&amp;quot;: &amp;quot;eslint \&amp;quot;src/**/*.js\&amp;quot; --fix&amp;quot;,
    &amp;quot;lint:check&amp;quot;: &amp;quot;eslint \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prettier&amp;quot;: &amp;quot;prettier --write \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prettier:check&amp;quot;: &amp;quot;prettier --check \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prepare&amp;quot;: &amp;quot;husky install&amp;quot;
  },
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;author&amp;quot;: {
    &amp;quot;name&amp;quot;: &amp;quot;YOUR_NAME&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;YOUR_EMAIL&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;YOUR_WEBSITE&amp;quot;
  },
  &amp;quot;homepage&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL#readme&amp;quot;,
  &amp;quot;repository&amp;quot;: {
    &amp;quot;type&amp;quot;: &amp;quot;git&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;git+YOUR_GIT_REPO_URL.git&amp;quot;
  },
  &amp;quot;bugs&amp;quot;: {
    &amp;quot;url&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL/issues&amp;quot;
  },
  &amp;quot;engines&amp;quot;: {
    &amp;quot;node&amp;quot;: &amp;quot;&amp;gt;=14.0.0&amp;quot;,
    &amp;quot;pnpm&amp;quot;: &amp;quot;&amp;gt;=8.0.0&amp;quot;
  },
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;@babel/core&amp;quot;: &amp;quot;7.18.5&amp;quot;,
    &amp;quot;@babel/preset-env&amp;quot;: &amp;quot;7.18.2&amp;quot;,
    &amp;quot;compression&amp;quot;: &amp;quot;1.7.4&amp;quot;,
    &amp;quot;cookie-parser&amp;quot;: &amp;quot;1.4.6&amp;quot;,
    &amp;quot;core-js&amp;quot;: &amp;quot;3.23.2&amp;quot;,
    &amp;quot;cors&amp;quot;: &amp;quot;2.8.5&amp;quot;,
    &amp;quot;crypto-js&amp;quot;: &amp;quot;4.1.1&amp;quot;,
    &amp;quot;dotenv&amp;quot;: &amp;quot;16.0.1&amp;quot;,
    &amp;quot;express&amp;quot;: &amp;quot;4.18.1&amp;quot;,
    &amp;quot;helmet&amp;quot;: &amp;quot;5.1.0&amp;quot;,
    &amp;quot;husky&amp;quot;: &amp;quot;8.0.1&amp;quot;,
    &amp;quot;jsonwebtoken&amp;quot;: &amp;quot;9.0.0&amp;quot;,
    &amp;quot;mongoose&amp;quot;: &amp;quot;6.11.3&amp;quot;,
    &amp;quot;regenerator-runtime&amp;quot;: &amp;quot;0.13.9&amp;quot;,
    &amp;quot;winston&amp;quot;: &amp;quot;3.8.0&amp;quot;
  },
  &amp;quot;devDependencies&amp;quot;: {
    &amp;quot;@babel/cli&amp;quot;: &amp;quot;7.17.10&amp;quot;,
    &amp;quot;@commitlint/cli&amp;quot;: &amp;quot;17.0.3&amp;quot;,
    &amp;quot;@commitlint/config-conventional&amp;quot;: &amp;quot;17.0.3&amp;quot;,
    &amp;quot;babel-plugin-module-resolver&amp;quot;: &amp;quot;4.1.0&amp;quot;,
    &amp;quot;eslint&amp;quot;: &amp;quot;8.18.0&amp;quot;,
    &amp;quot;eslint-config-airbnb-base&amp;quot;: &amp;quot;15.0.0&amp;quot;,
    &amp;quot;eslint-config-prettier&amp;quot;: &amp;quot;8.5.0&amp;quot;,
    &amp;quot;eslint-plugin-import&amp;quot;: &amp;quot;2.26.0&amp;quot;,
    &amp;quot;eslint-plugin-prettier&amp;quot;: &amp;quot;4.0.0&amp;quot;,
    &amp;quot;prettier&amp;quot;: &amp;quot;2.7.1&amp;quot;,
    &amp;quot;tsx&amp;quot;: &amp;quot;4.19.2&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;New you can run the application with &lt;code&gt;pnpm start&lt;/code&gt; or &lt;code&gt;pnpm dev&lt;/code&gt;, and you can also run the application with &lt;code&gt;pnpm build&lt;/code&gt; to create a production version.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm dev

pnpm start

pnpm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;New we&amp;#39;ll add a new package:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/compression&quot;&gt;compression&lt;/a&gt;: Your Node.js app&amp;#39;s main file contains middleware for &lt;code&gt;compression&lt;/code&gt;. GZIP, which supports a variety of &lt;code&gt;compression&lt;/code&gt; techniques, will then be enabled. Your JSON response and any static file replies will be smaller as a result.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add compression
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/cookie-parser&quot;&gt;cookie-parser&lt;/a&gt;: Your Node.js app&amp;#39;s main file contains middleware for &lt;code&gt;cookie-parser&lt;/code&gt;. This middleware will parse the cookies in the request and set them as properties of the request object.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add cookie-parser
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/core-js&quot;&gt;core-js&lt;/a&gt;: Your Node.js app&amp;#39;s main file contains middleware for &lt;code&gt;core-js&lt;/code&gt;. This middleware will add the necessary polyfills to your application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add core-js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/helmet&quot;&gt;helmet&lt;/a&gt;: Your Node.js app&amp;#39;s main file contains middleware for &lt;code&gt;helmet&lt;/code&gt;. This middleware will add security headers to your application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add helmet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/regenerator-runtime&quot;&gt;regenerator-runtime&lt;/a&gt;: Your Node.js app&amp;#39;s main file contains middleware for &lt;code&gt;regenerator-runtime&lt;/code&gt;. This middleware will add the necessary polyfills to your application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add regenerator-runtime
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we&amp;#39;ll change the &lt;code&gt;index.js&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import connectDb from &amp;#39;./config/db.config&amp;#39;;
//http constant
import ConstantHttpCode from &amp;#39;./constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;./constants/http.reason.constant&amp;#39;;
import {DATABASE_URL} from &amp;#39;./env/variable.env&amp;#39;;
import compression from &amp;#39;compression&amp;#39;;
import cookieParser from &amp;#39;cookie-parser&amp;#39;;
import cors from &amp;#39;cors&amp;#39;;
import express from &amp;#39;express&amp;#39;;
import helmet from &amp;#39;helmet&amp;#39;;

connectDb(DATABASE_URL);

const app = express();

//helmet
app.use(helmet());

app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(compression());
app.use(cors());
app.use(cookieParser());

app.get(&amp;#39;/&amp;#39;, (req, res, next) =&amp;gt; {
  try {
    res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      API: &amp;#39;Work&amp;#39;,
    });
  } catch (err) {
    next(err);
  }
});

export default app;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we&amp;#39;ll change the &lt;code&gt;bin/www.js&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;#!/user/bin/env node
import app from &amp;#39;..&amp;#39;;
import {PORT} from &amp;#39;../env/variable.env&amp;#39;;
import logger from &amp;#39;../utils/logger.util&amp;#39;;
import &amp;#39;core-js/stable&amp;#39;;
import http from &amp;#39;http&amp;#39;;
import &amp;#39;regenerator-runtime/runtime&amp;#39;;

/**
 * Normalize a port into a number, string, or false.
 */
const normalizePort = (val) =&amp;gt; {
  const port = parseInt(val, 10);

  if (Number.isNaN(port)) {
    // named pipe
    return val;
  }

  if (port &amp;gt;= 0) {
    // port number
    return port;
  }

  return false;
};

const port = normalizePort(PORT || &amp;#39;3000&amp;#39;);
app.set(&amp;#39;port&amp;#39;, port);

/**
 * Create HTTP server.
 */
const server = http.createServer(app);

/**
 * Event listener for HTTP server &amp;quot;error&amp;quot; event.
 */
const onError = (error) =&amp;gt; {
  if (error.syscall !== &amp;#39;listen&amp;#39;) {
    throw error;
  }

  const bind = typeof port === &amp;#39;string&amp;#39; ? `Pipe ${port}` : `Port ${port}`;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case &amp;#39;EACCES&amp;#39;:
      logger.error(`${bind} requires elevated privileges`);
      process.exit(1);
      break;
    case &amp;#39;EADDRINUSE&amp;#39;:
      logger.error(`${bind} is already in use`);
      process.exit(1);
      break;
    default:
      throw error;
  }
};

/**
 * Event listener for HTTP server &amp;quot;listening&amp;quot; event.
 */
const onListening = () =&amp;gt; {
  const addr = server.address();
  const bind = typeof addr === &amp;#39;string&amp;#39; ? `pipe ${addr}` : `port ${addr.port}`;
  logger.info(`Listening on ${bind}`);
};

server.listen(port);
server.on(&amp;#39;error&amp;#39;, onError);
server.on(&amp;#39;listening&amp;#39;, onListening);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;New we&amp;#39;ll run the application with &lt;code&gt;pnpm dev&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;╭─mkabumattar@mkabumattar in ~/work/tutorial is  v0.0.0 via  v18.3.0 took 243ms
╰─λ pnpm dev

&amp;gt; tutorial@0.0.0 dev
&amp;gt; tsx watch src/bin/www.js

2022-06-25 11:57:38:5738 info: Listening on port 3030
2022-06-25 11:57:38:5738 info: Mongo DB is connected to: 127.0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git Hooks&lt;/h2&gt;
&lt;p&gt;Before moving on to component development, there is one more section on configuration. If you want to expand on this project in the future, especially with a team of other developers, keep in mind that you&amp;#39;ll want it to be as stable as possible. To get it right from the beginning is time well spent.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re going to use a program called &lt;a href=&quot;https://husky.run/&quot;&gt;Husky&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Husky&lt;/h3&gt;
&lt;p&gt;Husky is a tool for executing scripts at various git stages, such as add, commit, push, etc. We would like to be able to specify requirements and, provided our project is of acceptable quality, only enable actions like commit and push to proceed if our code satisfies those requirements.&lt;/p&gt;
&lt;p&gt;To install Husky run&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add husky

git init

pnpm exec husky install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a &lt;code&gt;.husky&lt;/code&gt; directory in your project. Your hooks will be located here. As it is meant for other developers as well as yourself, make sure this directory is included in your code repository.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .gitignore
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of &amp;#39;npm pack&amp;#39;
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp
.cache

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;.husky&lt;/code&gt; directory will be created in your project by the second command. Your hooks will be located here. As it is meant for other developers as well as yourself, make sure this directory is included in your code repository.&lt;/p&gt;
&lt;p&gt;Add the following script to your &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;tutorial&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;0.0.0&amp;quot;,
  &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,
  &amp;quot;keywords&amp;quot;: [],
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;node build/bin/www.js&amp;quot;,
    &amp;quot;dev&amp;quot;: &amp;quot;tsx watch src/bin/www.js&amp;quot;,
    &amp;quot;clean&amp;quot;: &amp;quot;rm -rf build&amp;quot;,
    &amp;quot;build&amp;quot;: &amp;quot;pnpm clean &amp;amp;&amp;amp; pnpm exec babel src -d build --minified --presets @babel/preset-env&amp;quot;,
    &amp;quot;lint&amp;quot;: &amp;quot;eslint \&amp;quot;src/**/*.js\&amp;quot; --fix&amp;quot;,
    &amp;quot;lint:check&amp;quot;: &amp;quot;eslint \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prettier&amp;quot;: &amp;quot;prettier --write \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prettier:check&amp;quot;: &amp;quot;prettier --check \&amp;quot;src/**/*.js\&amp;quot;&amp;quot;,
    &amp;quot;prepare&amp;quot;: &amp;quot;husky install&amp;quot;
  },
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;author&amp;quot;: {
    &amp;quot;name&amp;quot;: &amp;quot;YOUR_NAME&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;YOUR_EMAIL&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;YOUR_WEBSITE&amp;quot;
  },
  &amp;quot;homepage&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL#readme&amp;quot;,
  &amp;quot;repository&amp;quot;: {
    &amp;quot;type&amp;quot;: &amp;quot;git&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;git+YOUR_GIT_REPO_URL.git&amp;quot;
  },
  &amp;quot;bugs&amp;quot;: {
    &amp;quot;url&amp;quot;: &amp;quot;YOUR_GIT_REPO_URL/issues&amp;quot;
  },
  &amp;quot;engines&amp;quot;: {
    &amp;quot;node&amp;quot;: &amp;quot;&amp;gt;=14.0.0&amp;quot;,
    &amp;quot;pnpm&amp;quot;: &amp;quot;&amp;gt;=8.0.0&amp;quot;
  },
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;@babel/core&amp;quot;: &amp;quot;7.18.5&amp;quot;,
    &amp;quot;@babel/preset-env&amp;quot;: &amp;quot;7.18.2&amp;quot;,
    &amp;quot;compression&amp;quot;: &amp;quot;1.7.4&amp;quot;,
    &amp;quot;cookie-parser&amp;quot;: &amp;quot;1.4.6&amp;quot;,
    &amp;quot;core-js&amp;quot;: &amp;quot;3.23.2&amp;quot;,
    &amp;quot;cors&amp;quot;: &amp;quot;2.8.5&amp;quot;,
    &amp;quot;crypto-js&amp;quot;: &amp;quot;4.1.1&amp;quot;,
    &amp;quot;dotenv&amp;quot;: &amp;quot;16.0.1&amp;quot;,
    &amp;quot;express&amp;quot;: &amp;quot;4.18.1&amp;quot;,
    &amp;quot;helmet&amp;quot;: &amp;quot;5.1.0&amp;quot;,
    &amp;quot;husky&amp;quot;: &amp;quot;8.0.1&amp;quot;,
    &amp;quot;jsonwebtoken&amp;quot;: &amp;quot;9.0.0&amp;quot;,
    &amp;quot;mongoose&amp;quot;: &amp;quot;6.11.3&amp;quot;,
    &amp;quot;regenerator-runtime&amp;quot;: &amp;quot;0.13.9&amp;quot;,
    &amp;quot;winston&amp;quot;: &amp;quot;3.8.0&amp;quot;
  },
  &amp;quot;devDependencies&amp;quot;: {
    &amp;quot;@babel/cli&amp;quot;: &amp;quot;7.17.10&amp;quot;,
    &amp;quot;@commitlint/cli&amp;quot;: &amp;quot;17.0.3&amp;quot;,
    &amp;quot;@commitlint/config-conventional&amp;quot;: &amp;quot;17.0.3&amp;quot;,
    &amp;quot;babel-plugin-module-resolver&amp;quot;: &amp;quot;4.1.0&amp;quot;,
    &amp;quot;eslint&amp;quot;: &amp;quot;8.18.0&amp;quot;,
    &amp;quot;eslint-config-airbnb-base&amp;quot;: &amp;quot;15.0.0&amp;quot;,
    &amp;quot;eslint-config-prettier&amp;quot;: &amp;quot;8.5.0&amp;quot;,
    &amp;quot;eslint-plugin-import&amp;quot;: &amp;quot;2.26.0&amp;quot;,
    &amp;quot;eslint-plugin-prettier&amp;quot;: &amp;quot;4.0.0&amp;quot;,
    &amp;quot;prettier&amp;quot;: &amp;quot;2.7.1&amp;quot;,
    &amp;quot;tsx&amp;quot;: &amp;quot;4.19.2&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To create a hook run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm exec husky add .husky/pre-commit &amp;quot;pnpm lint&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The aforementioned states that the &lt;code&gt;pnpm lint&lt;/code&gt; script must run and be successful before our commit may be successful. Success here refers to the absence of mistakes. You will be able to get warnings (remember in the ESLint config a setting of 1 is a warning and 2 is an error in case you want to adjust settings).&lt;/p&gt;
&lt;p&gt;We&amp;#39;re going to add another one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm exec husky add .husky/pre-push &amp;quot;pnpm build&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes sure that we can&amp;#39;t push to the remote repository until our code has built correctly. That sounds like a very acceptable requirement, don&amp;#39;t you think? By making this adjustment and attempting to push, feel free to test it.&lt;/p&gt;
&lt;h3&gt;Commitlint&lt;/h3&gt;
&lt;p&gt;Finally, we&amp;#39;ll add one more tool. Let&amp;#39;s make sure that everyone on the team is adhering to them as well (including ourselves! ), since we have been using a uniform format for all of our commit messages so far. For our commit messages, we may add a linter.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add -D @commitlint/config-conventional @commitlint/cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will configure it using a set of common defaults, but since I occasionally forget what prefixes are available, I like to explicitly provide that list in a &lt;code&gt;commitlint.config.js&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch commitlint.config.js
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
// ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
// docs: Documentation only changes
// feat: A new feature
// fix: A bug fix
// perf: A code change that improves performance
// refactor: A code change that neither fixes a bug nor adds a feature
// style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
// test: Adding missing tests or correcting existing tests

module.exports = {
  extends: [&amp;#39;@commitlint/config-conventional&amp;#39;],
  rules: {
    &amp;#39;body-leading-blank&amp;#39;: [1, &amp;#39;always&amp;#39;],
    &amp;#39;body-max-line-length&amp;#39;: [2, &amp;#39;always&amp;#39;, 100],
    &amp;#39;footer-leading-blank&amp;#39;: [1, &amp;#39;always&amp;#39;],
    &amp;#39;footer-max-line-length&amp;#39;: [2, &amp;#39;always&amp;#39;, 100],
    &amp;#39;header-max-length&amp;#39;: [2, &amp;#39;always&amp;#39;, 100],
    &amp;#39;scope-case&amp;#39;: [2, &amp;#39;always&amp;#39;, &amp;#39;lower-case&amp;#39;],
    &amp;#39;subject-case&amp;#39;: [
      2,
      &amp;#39;never&amp;#39;,
      [&amp;#39;sentence-case&amp;#39;, &amp;#39;start-case&amp;#39;, &amp;#39;pascal-case&amp;#39;, &amp;#39;upper-case&amp;#39;],
    ],
    &amp;#39;subject-empty&amp;#39;: [2, &amp;#39;never&amp;#39;],
    &amp;#39;subject-full-stop&amp;#39;: [2, &amp;#39;never&amp;#39;, &amp;#39;.&amp;#39;],
    &amp;#39;type-case&amp;#39;: [2, &amp;#39;always&amp;#39;, &amp;#39;lower-case&amp;#39;],
    &amp;#39;type-empty&amp;#39;: [2, &amp;#39;never&amp;#39;],
    &amp;#39;type-enum&amp;#39;: [
      2,
      &amp;#39;always&amp;#39;,
      [
        &amp;#39;build&amp;#39;,
        &amp;#39;chore&amp;#39;,
        &amp;#39;ci&amp;#39;,
        &amp;#39;docs&amp;#39;,
        &amp;#39;feat&amp;#39;,
        &amp;#39;fix&amp;#39;,
        &amp;#39;perf&amp;#39;,
        &amp;#39;refactor&amp;#39;,
        &amp;#39;revert&amp;#39;,
        &amp;#39;style&amp;#39;,
        &amp;#39;test&amp;#39;,
        &amp;#39;translation&amp;#39;,
        &amp;#39;security&amp;#39;,
        &amp;#39;changeset&amp;#39;,
      ],
    ],
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Afterward, use Husky to enable commitlint by using:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm exec husky add .husky/commit-msg &amp;#39;pnpm exec commitlint --edit &amp;quot;$1&amp;quot;&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now connect this repository to GitHub and push your commits. This uses an SSH remote (&lt;code&gt;git@github.com:&lt;/code&gt;), so set up your &lt;a href=&quot;/blog/post/git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux&quot;&gt;SSH keys&lt;/a&gt; first if you haven&amp;#39;t already.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;echo &amp;quot;# Setting up Node JS, Express, MongoDB, Prettier, ESLint and Husky Application with Babel and authentication as an example&amp;quot; &amp;gt;&amp;gt; README.md
git init
git add README.md
git commit -m &amp;quot;ci: Initial commit&amp;quot;
git branch -M main
git remote add origin git@github.com:&amp;lt;your-github-username&amp;gt;/&amp;lt;your-github-repository-name&amp;gt;.git
git push -u origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;VS Code&lt;/h2&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;We can now take advantage of some useful VS Code functionality to have ESLint and Prettier run automatically since we have implemented them.&lt;/p&gt;
&lt;p&gt;Make a &lt;code&gt;settings.json&lt;/code&gt; file and a directory called &lt;code&gt;.vscode&lt;/code&gt; at the top of your project. This will be a list of values that overrides the VS Code installation&amp;#39;s default settings.&lt;/p&gt;
&lt;p&gt;Because we may set up particular parameters that only apply to this project and share them with the rest of our team by adding them to the code repository, we want to put them in a folder for the project.&lt;/p&gt;
&lt;p&gt;Within &lt;code&gt;settings.json&lt;/code&gt; we will add the following values:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mkdir .vscode
touch .vscode/settings.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;settings.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;editor.defaultFormatter&amp;quot;: &amp;quot;esbenp.prettier-vscode&amp;quot;,
  &amp;quot;editor.formatOnSave&amp;quot;: true,
  &amp;quot;editor.codeActionsOnSave&amp;quot;: {
    &amp;quot;source.fixAll&amp;quot;: true,
    &amp;quot;source.organizeImports&amp;quot;: true
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Debugging&lt;/h3&gt;
&lt;p&gt;In case we encounter any problems while developing our program, let&amp;#39;s set up a handy environment for debugging.&lt;/p&gt;
&lt;p&gt;Inside of your &lt;code&gt;.vscode&lt;/code&gt; directory create a &lt;code&gt;launch.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .vscode/launch.json
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;version&amp;quot;: &amp;quot;0.1.0&amp;quot;,
  &amp;quot;configurations&amp;quot;: [
    {
      &amp;quot;name&amp;quot;: &amp;quot;debug server&amp;quot;,
      &amp;quot;type&amp;quot;: &amp;quot;node-terminal&amp;quot;,
      &amp;quot;request&amp;quot;: &amp;quot;launch&amp;quot;,
      &amp;quot;command&amp;quot;: &amp;quot;pnpm dev&amp;quot;
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Authentication&lt;/h2&gt;
&lt;h3&gt;Authentication Setup&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ll add a new packages to our project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/crypto-js&quot;&gt;crypto-js&lt;/a&gt;: A JavaScript library for encryption and decryption.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/jsonwebtoken&quot;&gt;jsonwebtoken&lt;/a&gt;: A JavaScript library for creating and verifying JSON Web Tokens.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pnpm add crypto-js jsonwebtoken
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;add secret key to &lt;code&gt;.env&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;...
JWT_SECRET=secret
PASS_SECRET=secret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;add &lt;code&gt;JWT_SECRET&lt;/code&gt; and &lt;code&gt;PASS_SECRET&lt;/code&gt; to &lt;code&gt;variable.env.js&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;...

export const { JWT_SECRET } = process.env
export const { PASS_SECRET } = process.env

export default {
  ...,
  JWT_SECRET,
  PASS_SECRET,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;know we&amp;#39;ll add the constants to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// api
export const API_AUTH = &amp;#39;/api/auth&amp;#39;;
export const API_USERS = &amp;#39;/api/users&amp;#39;;

// auth
export const AUTH_REGISTER = &amp;#39;/register&amp;#39;;
export const AUTH_LOGIN = &amp;#39;/login&amp;#39;;

// users
export const USER_UPDATE_USERNAME = &amp;#39;/update-username/:id&amp;#39;;
export const USER_UPDATE_NAME = &amp;#39;/update-name/:id&amp;#39;;
export const USER_UPDATE_EMAIL = &amp;#39;/update-email/:id&amp;#39;;
export const USER_UPDATE_PASSWORD = &amp;#39;/update-password/:id&amp;#39;;
export const USER_UPDATE_PHONE = &amp;#39;/update-phone/:id&amp;#39;;
export const USER_UPDATE_ADDRESS = &amp;#39;/update-address/:id&amp;#39;;
export const USER_DELETE = &amp;#39;/delete/:id&amp;#39;;
export const USER_GET = &amp;#39;/find/:id&amp;#39;;
export const USER_GET_ALL = &amp;#39;/&amp;#39;;
export const USER_GET_ALL_STATS = &amp;#39;/stats&amp;#39;;

export default {
  // api
  API_AUTH,
  API_USERS,

  // auth
  AUTH_REGISTER,
  AUTH_LOGIN,

  // users
  USER_UPDATE_USERNAME,
  USER_UPDATE_NAME,
  USER_UPDATE_EMAIL,
  USER_UPDATE_PASSWORD,
  USER_UPDATE_PHONE,
  USER_UPDATE_ADDRESS,
  USER_DELETE,
  USER_GET,
  USER_GET_ALL,
  USER_GET_ALL_STATS,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// token
export const TOKEN_NOT_VALID = &amp;#39;Token not valid&amp;#39;;
export const NOT_AUTHENTICATED = &amp;#39;Not authenticated&amp;#39;;
export const NOT_ALLOWED = &amp;#39;Not allowed&amp;#39;;

// auth
export const USERNAME_NOT_VALID = &amp;#39;username is not valid&amp;#39;;
export const NAME_NOT_VALID = &amp;#39;name is not valid&amp;#39;;
export const EMAIL_NOT_VALID = &amp;#39;email is not valid&amp;#39;;
export const PASSWORD_NOT_VALID = &amp;#39;password is not valid&amp;#39;;
export const PHONE_NOT_VALID = &amp;#39;phone is not valid&amp;#39;;
export const ADDRESS_NOT_VALID = &amp;#39;address is not valid&amp;#39;;
export const USERNAME_EXIST = &amp;#39;username is exist&amp;#39;;
export const EMAIL_EXIST = &amp;#39;email is exist&amp;#39;;
export const PHONE_EXIST = &amp;#39;phone is exist&amp;#39;;
export const USER_NOT_CREATE = &amp;#39;user is not create, please try again&amp;#39;;
export const USER_CREATE_SUCCESS = &amp;#39;user is create success, please login&amp;#39;;
export const USER_NOT_FOUND = &amp;#39;user is not found&amp;#39;;
export const PASSWORD_NOT_MATCH = &amp;#39;password is not match&amp;#39;;
export const USER_LOGIN_SUCCESS = &amp;#39;user is login success&amp;#39;;

// user
export const USERNAME_NOT_CHANGE = &amp;#39;username is not change&amp;#39;;
export const USERNAME_CHANGE_SUCCESS = &amp;#39;username is change success&amp;#39;;
export const NAME_NOT_CHANGE = &amp;#39;name is not change&amp;#39;;
export const NAME_CHANGE_SUCCESS = &amp;#39;name is change success&amp;#39;;
export const EMAIL_NOT_CHANGE = &amp;#39;email is not change&amp;#39;;
export const EMAIL_CHANGE_SUCCESS = &amp;#39;email is change success&amp;#39;;
export const PASSWORD_NOT_CHANGE = &amp;#39;password is not change&amp;#39;;
export const PASSWORD_CHANGE_SUCCESS = &amp;#39;password is change success&amp;#39;;
export const PHONE_NOT_CHANGE = &amp;#39;phone is not change&amp;#39;;
export const PHONE_CHANGE_SUCCESS = &amp;#39;phone is change success&amp;#39;;
export const ADDRESS_NOT_CHANGE = &amp;#39;address is not change&amp;#39;;
export const ADDRESS_CHANGE_SUCCESS = &amp;#39;address is change success&amp;#39;;
export const USER_NOT_DELETE = &amp;#39;user is not delete, please try again&amp;#39;;
export const USER_DELETE_SUCCESS = &amp;#39;user is delete success&amp;#39;;
export const USER_FOUND = &amp;#39;user is found&amp;#39;;

export default {
  // token
  TOKEN_NOT_VALID,
  NOT_AUTHENTICATED,
  NOT_ALLOWED,

  // auth
  USERNAME_NOT_VALID,
  NAME_NOT_VALID,
  EMAIL_NOT_VALID,
  PASSWORD_NOT_VALID,
  PHONE_NOT_VALID,
  ADDRESS_NOT_VALID,
  USERNAME_EXIST,
  EMAIL_EXIST,
  PHONE_EXIST,
  USER_NOT_CREATE,
  USER_CREATE_SUCCESS,
  USER_NOT_FOUND,
  PASSWORD_NOT_MATCH,
  USER_LOGIN_SUCCESS,

  // user
  USERNAME_NOT_CHANGE,
  USERNAME_CHANGE_SUCCESS,
  NAME_NOT_CHANGE,
  NAME_CHANGE_SUCCESS,
  EMAIL_NOT_CHANGE,
  EMAIL_CHANGE_SUCCESS,
  PASSWORD_NOT_CHANGE,
  PASSWORD_CHANGE_SUCCESS,
  PHONE_NOT_CHANGE,
  PHONE_CHANGE_SUCCESS,
  ADDRESS_NOT_CHANGE,
  ADDRESS_CHANGE_SUCCESS,
  USER_NOT_DELETE,
  USER_DELETE_SUCCESS,
  USER_FOUND,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const USER_MODEL = &amp;#39;UserModel&amp;#39;;

export default {
  USER_MODEL,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// user
export const USERNAME_MIN_LENGTH = 3;
export const USERNAME_MAX_LENGTH = 20;
export const NAME_MIN_LENGTH = 3;
export const NAME_MAX_LENGTH = 80;
export const EMAIL_MAX_LENGTH = 50;
export const PASSWORD_MIN_LENGTH = 8;
export const PHONE_MIN_LENGTH = 10;
export const PHONE_MAX_LENGTH = 20;
export const ADDRESS_MIN_LENGTH = 10;
export const ADDRESS_MAX_LENGTH = 200;

export default {
  USERNAME_MIN_LENGTH,
  USERNAME_MAX_LENGTH,
  NAME_MIN_LENGTH,
  NAME_MAX_LENGTH,
  EMAIL_MAX_LENGTH,
  PASSWORD_MIN_LENGTH,
  PHONE_MIN_LENGTH,
  PHONE_MAX_LENGTH,
  ADDRESS_MIN_LENGTH,
  ADDRESS_MAX_LENGTH,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const USERNAME = /^(?!.*\.\.)(?!.*\.$)[^\W][\w.]{3,32}$/;
export const EMAIL =
  /^(([^&amp;lt;&amp;gt;()\\[\]\\.,;:\s@&amp;quot;]+(\.[^&amp;lt;&amp;gt;()\\[\]\\.,;:\s@&amp;quot;]+)*)|(&amp;quot;.+&amp;quot;))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
export const PASSWORD =
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&amp;amp;])[A-Za-z\d@$!%*?&amp;amp;]{8,}$/;
export const NAME = /^[a-zA-Z ]{2,35}$/;
export const PHONE =
  /^\s*(?:\+?(\d{1,3}))?([-. (]*(\d{3})[-. )]*)?((\d{3})[-. ]*(\d{2,4})(?:[-.x ]*(\d+))?)\s*$/gm;
export const ADDRESS = /^[a-zA-Z0-9\s,&amp;#39;-]{10,200}$/;

export default {
  USERNAME,
  EMAIL,
  PASSWORD,
  NAME,
  PHONE,
  ADDRESS,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication Middleware&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// http constant
import ConstantHttpCode from &amp;#39;../constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;../constants/http.reason.constant&amp;#39;;
import ConstantMessage from &amp;#39;../constants/message.constant&amp;#39;;
import {JWT_SECRET} from &amp;#39;../env/variable.env&amp;#39;;
// logger
import logger from &amp;#39;../utils/logger.util&amp;#39;;
import jwt from &amp;#39;jsonwebtoken&amp;#39;;

export const verifyToken = (req, res, next) =&amp;gt; {
  const authHeader = req.headers.token;
  logger.info(`authHeader: ${authHeader}`);
  if (authHeader) {
    const token = authHeader.split(&amp;#39; &amp;#39;)[1];
    return jwt.verify(token, JWT_SECRET, (err, user) =&amp;gt; {
      if (err) {
        res.status(ConstantHttpCode.FORBIDDEN).json({
          status: {
            code: ConstantHttpCode.FORBIDDEN,
            msg: ConstantHttpReason.FORBIDDEN,
          },
          msg: ConstantMessage.TOKEN_NOT_VALID,
        });
      }
      req.user = user;
      return next();
    });
  }

  return res.status(ConstantHttpCode.UNAUTHORIZED).json({
    status: {
      code: ConstantHttpCode.UNAUTHORIZED,
      msg: ConstantHttpReason.UNAUTHORIZED,
    },
    msg: ConstantMessage.NOT_AUTHENTICATED,
  });
};

export const verifyTokenAndAuthorization = (req, res, next) =&amp;gt; {
  verifyToken(req, res, () =&amp;gt; {
    if (req.user.id === req.params.id || req.user.isAdmin) {
      return next();
    }

    return res.status(ConstantHttpCode.FORBIDDEN).json({
      status: {
        code: ConstantHttpCode.FORBIDDEN,
        msg: ConstantHttpReason.FORBIDDEN,
      },
      msg: ConstantMessage.NOT_ALLOWED,
    });
  });
};

export const verifyTokenAndAdmin = (req, res, next) =&amp;gt; {
  verifyToken(req, res, () =&amp;gt; {
    if (req.user.isAdmin) {
      return next();
    }

    return res.status(ConstantHttpCode.FORBIDDEN).json({
      status: {
        code: ConstantHttpCode.FORBIDDEN,
        msg: ConstantHttpReason.FORBIDDEN,
      },
      msg: ConstantMessage.NOT_ALLOWED,
    });
  });
};

export default {
  verifyToken,
  verifyTokenAndAuthorization,
  verifyTokenAndAdmin,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication Security&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import {JWT_SECRET, PASS_SECRET} from &amp;#39;../env/variable.env&amp;#39;;
import CryptoJS from &amp;#39;crypto-js&amp;#39;;
import jwt from &amp;#39;jsonwebtoken&amp;#39;;

export const encryptedPassword = (password) =&amp;gt; {
  return CryptoJS.AES.encrypt(password, PASS_SECRET).toString();
};

export const decryptedPassword = (password) =&amp;gt; {
  return CryptoJS.AES.decrypt(password, PASS_SECRET).toString(
    CryptoJS.enc.Utf8,
  );
};

export const comparePassword = (password, dPassword) =&amp;gt; {
  const compare = decryptedPassword(dPassword) === password;
  return compare;
};

export const generateAccessToken = (id, isAdmin) =&amp;gt; {
  return jwt.sign({id, isAdmin}, JWT_SECRET, {expiresIn: &amp;#39;3d&amp;#39;});
};

export default {
  encryptedPassword,
  decryptedPassword,
  comparePassword,
  generateAccessToken,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication validations&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import ConstantRegex from &amp;#39;../constants/regex.constant&amp;#39;;

export const validateUsername = async (username) =&amp;gt; {
  return ConstantRegex.USERNAME.test(username);
};

export const validateName = async (name) =&amp;gt; {
  return ConstantRegex.NAME.test(name);
};

export const validateEmail = async (email) =&amp;gt; {
  return ConstantRegex.EMAIL.test(email);
};

export const validatePassword = async (password) =&amp;gt; {
  return ConstantRegex.PASSWORD.test(password);
};

export const validatePhone = async (phone) =&amp;gt; {
  return ConstantRegex.PHONE.test(phone);
};

export const validateAddress = async (address) =&amp;gt; {
  return ConstantRegex.ADDRESS.test(address);
};

export default {
  validateUsername,
  validateName,
  validateEmail,
  validatePassword,
  validatePhone,
  validateAddress,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication schemas&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import ConstantNumber from &amp;#39;../constants/number.constant&amp;#39;;
import mongoose from &amp;#39;mongoose&amp;#39;;

const UserSchema = new mongoose.Schema(
  {
    username: {
      type: String,
      required: true,
      unique: true,
      min: ConstantNumber.USERNAME_MIN_LENGTH,
      max: ConstantNumber.USERNAME_MAX_LENGTH,
    },
    name: {
      type: String,
      required: true,
      min: ConstantNumber.NAME_MIN_LENGTH,
      max: ConstantNumber.NAME_MAX_LENGTH,
    },
    email: {
      type: String,
      required: true,
      unique: true,
      max: ConstantNumber.EMAIL_MAX_LENGTH,
    },
    password: {
      type: String,
      required: true,
      min: ConstantNumber.PASSWORD_MIN_LENGTH,
    },
    phone: {
      type: String,
      required: true,
      unique: true,
      min: ConstantNumber.PHONE_MIN_LENGTH,
      max: ConstantNumber.PHONE_MAX_LENGTH,
    },
    address: {
      type: String,
      required: true,
      min: ConstantNumber.ADDRESS_MIN_LENGTH,
      max: ConstantNumber.ADDRESS_MAX_LENGTH,
    },
    isAdmin: {
      type: Boolean,
      default: true,
    },
  },
  {
    versionKey: false,
    timestamps: true,
  },
);

export default UserSchema;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication Models&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import ConstantModel from &amp;#39;../constants/model.constant&amp;#39;;
import UserSchema from &amp;#39;../schemas/user.schema&amp;#39;;
import mongoose from &amp;#39;mongoose&amp;#39;;

const UserModel = mongoose.model(ConstantModel.USER_MODEL, UserSchema);

export default UserModel;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication Repositories&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import User from &amp;#39;../models/user.model&amp;#39;;

export const findAll = async () =&amp;gt; {
  const users = await User.find({}).select(&amp;#39;-password&amp;#39;);
  return users;
};

export const findById = async (id) =&amp;gt; {
  const user = await User.findById(id).select(&amp;#39;-password&amp;#39;);
  return user;
};

export const findByIdWithPassword = async (id) =&amp;gt; {
  const user = await User.findById(id);
  return user;
};

export const findByUser = async (username) =&amp;gt; {
  const user = await User.findOne({username}).select(&amp;#39;-password&amp;#39;);
  return user;
};

export const findByEmail = async (email) =&amp;gt; {
  const user = await User.findOne({email}).select(&amp;#39;-password&amp;#39;);
  return user;
};

export const findByEmailWithPassword = async (email) =&amp;gt; {
  const user = await User.findOne({email});
  return user;
};

export const findByPhone = async (phone) =&amp;gt; {
  const user = await User.findOne({phone}).select(&amp;#39;-password&amp;#39;);
  return user;
};

export const createUser = async (user) =&amp;gt; {
  const newUser = new User({
    username: user.username,
    name: user.name,
    email: user.email,
    password: user.password,
    phone: user.phone,
    address: user.address,
    isAdmin: user.isAdmin,
  });
  const savedUser = await newUser.save();
  return savedUser;
};

export const updateUsername = async (id, username) =&amp;gt; {
  const user = await User.findByIdAndUpdate(id, {username}, {new: true}).select(
    &amp;#39;-password&amp;#39;,
  );
  return user;
};

export const updateName = async (id, name) =&amp;gt; {
  const user = await User.findByIdAndUpdate(id, {name}, {new: true}).select(
    &amp;#39;-password&amp;#39;,
  );
  return user;
};

export const updateEmail = async (id, email) =&amp;gt; {
  const user = await User.findByIdAndUpdate(id, {email}, {new: true}).select(
    &amp;#39;-password&amp;#39;,
  );
  return user;
};

export const updatePassword = async (id, password) =&amp;gt; {
  const user = await User.findByIdAndUpdate(id, {password}, {new: true}).select(
    &amp;#39;-password&amp;#39;,
  );
  return user;
};

export const updatePhone = async (id, phone) =&amp;gt; {
  const user = await User.findByIdAndUpdate(id, {phone}, {new: true}).select(
    &amp;#39;-password&amp;#39;,
  );
  return user;
};

export const updateAddress = async (id, address) =&amp;gt; {
  const user = await User.findByIdAndUpdate(id, {address}, {new: true}).select(
    &amp;#39;-password&amp;#39;,
  );
  return user;
};

export const deleteUser = async (id) =&amp;gt; {
  const user = await User.findByIdAndDelete(id);
  return user;
};

export const getUsersStats = async (lastYear) =&amp;gt; {
  const users = await User.aggregate([
    {$match: {createdAt: {$gte: lastYear}}},
    {
      $project: {
        month: {$month: &amp;#39;$createdAt&amp;#39;},
      },
    },
    {
      $group: {
        _id: &amp;#39;$month&amp;#39;,
        total: {$sum: 1},
      },
    },
  ]);
  return users;
};

export default {
  findAll,
  findById,
  findByIdWithPassword,
  findByUser,
  findByEmail,
  findByEmailWithPassword,
  findByPhone,
  createUser,
  updateUsername,
  updateName,
  updateEmail,
  updatePassword,
  updatePhone,
  updateAddress,
  deleteUser,
  getUsersStats,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication Services&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import UserRepository from &amp;#39;../repositories/user.repository&amp;#39;;
import UserSecurity from &amp;#39;../security/user.security&amp;#39;;
import UserValidation from &amp;#39;../validations/user.validation&amp;#39;;

export const validateUsername = (username) =&amp;gt; {
  return UserValidation.validateUsername(username);
};

export const validateName = (name) =&amp;gt; {
  return UserValidation.validateName(name);
};

export const validateEmail = (email) =&amp;gt; {
  return UserValidation.validateEmail(email);
};

export const validatePassword = (password) =&amp;gt; {
  return UserValidation.validatePassword(password);
};

export const comparePassword = (password, encryptedPassword) =&amp;gt; {
  return UserSecurity.comparePassword(password, encryptedPassword);
};

export const validatePhone = (phone) =&amp;gt; {
  return UserValidation.validatePhone(phone);
};

export const validateAddress = (address) =&amp;gt; {
  return UserValidation.validateAddress(address);
};

export const findByUser = async (username) =&amp;gt; {
  const user = await UserRepository.findByUser(username);
  return user;
};

export const findByEmail = async (email) =&amp;gt; {
  const user = await UserRepository.findByEmailWithPassword(email);
  return user;
};

export const findByPhone = async (phone) =&amp;gt; {
  const user = await UserRepository.findByPhone(phone);
  return user;
};

export const createUser = async (user) =&amp;gt; {
  const encryptedPassword = UserSecurity.encryptedPassword(user.password);
  const newUser = {
    username: user.username,
    name: user.name,
    email: user.email,
    password: encryptedPassword,
    phone: user.phone,
    address: user.address,
    isAdmin: user.isAdmin,
  };
  const savedUser = await UserRepository.createUser(newUser);
  return savedUser;
};

export const generateAccessToken = async (user) =&amp;gt; {
  return `Bearer ${UserSecurity.generateAccessToken(user.id, user.isAdmin)}`;
};

export default {
  validateUsername,
  validateName,
  validateEmail,
  validatePassword,
  comparePassword,
  validatePhone,
  validateAddress,
  findByUser,
  findByEmail,
  findByPhone,
  createUser,
  generateAccessToken,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import UserRepository from &amp;#39;../repositories/user.repository&amp;#39;;
import UserSecurity from &amp;#39;../security/user.security&amp;#39;;
import UserValidation from &amp;#39;../validations/user.validation&amp;#39;;

export const validateUsername = (username) =&amp;gt; {
  return UserValidation.validateUsername(username);
};

export const validateName = (name) =&amp;gt; {
  return UserValidation.validateName(name);
};

export const validateEmail = (email) =&amp;gt; {
  return UserValidation.validateEmail(email);
};

export const validatePassword = (name) =&amp;gt; {
  return UserValidation.validatePassword(name);
};

export const comparePassword = (password, encryptedPassword) =&amp;gt; {
  return UserSecurity.comparePassword(password, encryptedPassword);
};

export const validatePhone = (phone) =&amp;gt; {
  return UserValidation.validatePhone(phone);
};

export const validateAddress = (address) =&amp;gt; {
  return UserValidation.validateAddress(address);
};

export const findAll = async () =&amp;gt; {
  const users = await UserRepository.findAll();
  return users;
};

export const findById = async (id) =&amp;gt; {
  const user = await UserRepository.findByIdWithPassword(id);
  return user;
};

export const findByIdWithOutPassword = async (id) =&amp;gt; {
  const user = await UserRepository.findById(id);
  return user;
};

export const findByEmail = async (email) =&amp;gt; {
  const user = await UserRepository.findByEmail(email);
  return user;
};

export const findByPhone = async (phone) =&amp;gt; {
  const user = await UserRepository.findByPhone(phone);
  return user;
};

export const findByUser = async (username) =&amp;gt; {
  const user = await UserRepository.findByUser(username);
  return user;
};

export const updateUsername = async (id, username) =&amp;gt; {
  const user = await UserRepository.updateUsername(id, username);
  return user;
};

export const updateName = async (id, name) =&amp;gt; {
  const user = await UserRepository.updateName(id, name);
  return user;
};

export const updateEmail = async (id, email) =&amp;gt; {
  const user = await UserRepository.updateEmail(id, email);
  return user;
};

export const updatePassword = async (id, password) =&amp;gt; {
  const encryptedPassword = UserSecurity.encryptedPassword(password);
  const user = await UserRepository.updatePassword(id, encryptedPassword);
  return user;
};

export const updatePhone = async (id, phone) =&amp;gt; {
  const user = await UserRepository.updatePhone(id, phone);
  return user;
};

export const updateAddress = async (id, address) =&amp;gt; {
  const user = await UserRepository.updateAddress(id, address);
  return user;
};

export const deleteUser = async (id) =&amp;gt; {
  const user = await UserRepository.deleteUser(id);
  return user;
};

export const getUsersStats = async () =&amp;gt; {
  const users = await UserRepository.getUsersStats();
  return users;
};

export default {
  validateUsername,
  validateName,
  validateEmail,
  validatePassword,
  comparePassword,
  validatePhone,
  validateAddress,
  findAll,
  findById,
  findByIdWithOutPassword,
  findByEmail,
  findByPhone,
  findByUser,
  updateUsername,
  updateName,
  updateEmail,
  updatePassword,
  updatePhone,
  updateAddress,
  deleteUser,
  getUsersStats,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication Controllers&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;auth.controller.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// http constant
import ConstantHttpCode from &amp;#39;../constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;../constants/http.reason.constant&amp;#39;;
import ConstantMessage from &amp;#39;../constants/message.constant&amp;#39;;
import AuthServices from &amp;#39;../services/auth.service&amp;#39;;
// logger
import logger from &amp;#39;../utils/logger.util&amp;#39;;

export const register = async (req, res, next) =&amp;gt; {
  try {
    const {username, name, email, password, phone, address} = req.body;

    const usernameValidated = AuthServices.validateUsername(username);
    if (!usernameValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.USERNAME_NOT_VALID,
      });
    }
    logger.info(`username ${username} is valid`);

    const nameValidated = AuthServices.validateName(name);
    if (!nameValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.NAME_NOT_VALID,
      });
    }
    logger.info(`name ${name} is valid`);

    const emailValidated = AuthServices.validateEmail(email);
    if (!emailValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.EMAIL_NOT_VALID,
      });
    }
    logger.info(`email ${email} is valid`);

    const passwordValidated = AuthServices.validatePassword(password);
    if (!passwordValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_VALID,
      });
    }

    const phoneValidated = AuthServices.validatePhone(phone);
    if (!phoneValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PHONE_NOT_VALID,
      });
    }

    const addressValidated = AuthServices.validateAddress(address);
    if (!addressValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.ADDRESS_NOT_VALID,
      });
    }

    const usernameCheck = await AuthServices.findByUser(username);
    if (usernameCheck) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.USERNAME_EXIST,
      });
    }

    const emailCheck = await AuthServices.findByEmail(email);
    if (emailCheck) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.EMAIL_EXIST,
      });
    }

    const phoneCheck = await AuthServices.findByPhone(phone);
    if (phoneCheck) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PHONE_EXIST,
      });
    }

    const newUserData = {
      username,
      name,
      email,
      password,
      phone,
      address,
    };

    const user = await AuthServices.createUser(newUserData);
    if (!user) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.USER_NOT_CREATE,
      });
    }

    const newUser = {...user}._doc;

    logger.info({newUserpassword: newUser.password});

    delete newUser.password;

    logger.info({newUserpassword: newUser.password});

    return res.status(ConstantHttpCode.CREATED).json({
      status: {
        code: ConstantHttpCode.CREATED,
        msg: ConstantHttpReason.CREATED,
      },
      msg: ConstantMessage.USER_CREATE_SUCCESS,
      data: user,
    });
  } catch (err) {
    return next(err);
  }
};

export const login = async (req, res, next) =&amp;gt; {
  try {
    const {email, password} = req.body;

    const emailValidated = AuthServices.validateEmail(email);
    if (!emailValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.EMAIL_NOT_VALID,
      });
    }

    const passwordValidated = AuthServices.validatePassword(password);
    if (!passwordValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_VALID,
      });
    }

    const user = await AuthServices.findByEmail(email);
    if (!user) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }

    const isMatch = AuthServices.comparePassword(password, user.password);
    if (!isMatch) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_MATCH,
      });
    }

    const accessToken = await AuthServices.generateAccessToken(user);
    logger.info(`accessToken: ${accessToken}`);

    const newUser = {...user}._doc;

    logger.info({newUserpassword: newUser.password});

    delete newUser.password;

    logger.info({newUserpassword: newUser.password});

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.LOGIN_SUCCESS,
      data: {
        user,
        accessToken,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export default {
  register,
  login,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;user.controller.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// http constant
import ConstantHttpCode from &amp;#39;../constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;../constants/http.reason.constant&amp;#39;;
import ConstantMessage from &amp;#39;../constants/message.constant&amp;#39;;
import UserService from &amp;#39;../services/user.service&amp;#39;;
// logger
import logger from &amp;#39;../utils/logger.util&amp;#39;;

export const updateUsername = async (req, res, next) =&amp;gt; {
  try {
    const {username, password} = req.body;
    const {id} = req.params;

    const user = await UserService.findById(id);
    if (!user) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`user ${user.username} found`);

    const usernameValidated = UserService.validateUsername(username);
    if (!usernameValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.USERNAME_NOT_VALID,
      });
    }
    logger.info(`username ${username} is valid`);

    const passwordValidated = UserService.validatePassword(password);
    if (!passwordValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_VALID,
      });
    }
    logger.info(`password ${password} is valid`);

    const isMatch = UserService.comparePassword(password, user.password);
    if (!isMatch) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_MATCH,
      });
    }

    const usernameCheck = await UserService.findByUser(username);
    if (usernameCheck) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.USERNAME_EXIST,
      });
    }

    if (user.username === username) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.USERNAME_NOT_CHANGE,
      });
    }

    const updatedUser = await UserService.updateUsername(id, username);
    if (!updatedUser) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.USERNAME_NOT_CHANGE,
      });
    }
    logger.info(`user ${user.username} updated`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.USERNAME_CHANGE_SUCCESS,
      data: {
        user: updatedUser,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export const updateName = async (req, res, next) =&amp;gt; {
  try {
    const {name, password} = req.body;
    const {id} = req.params;

    const user = await UserService.findById(id);
    if (!user) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`user ${user.username} found`);

    const nameValidated = UserService.validateName(name);
    if (!nameValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.NAME_NOT_VALID,
      });
    }

    const passwordValidated = UserService.validatePassword(password);
    if (!passwordValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_VALID,
      });
    }

    const isMatch = UserService.comparePassword(password, user.password);
    if (!isMatch) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_MATCH,
      });
    }
    logger.info(`password ${password} is valid`);

    if (user.name === name) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.NAME_NOT_CHANGE,
      });
    }
    logger.info(`name ${name} is valid`);

    const updatedUser = await UserService.updateName(id, name);
    if (!updatedUser) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.NAME_NOT_CHANGE,
      });
    }
    logger.info(`user ${user.username} updated`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.NAME_CHANGE_SUCCESS,
      data: {
        user: updatedUser,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export const updateEmail = async (req, res, next) =&amp;gt; {
  try {
    const {email, password} = req.body;
    const {id} = req.params;

    const user = await UserService.findById(id);
    if (!user) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`user ${user.username} found`);

    const emailValidated = UserService.validateEmail(email);
    if (!emailValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.EMAIL_NOT_VALID,
      });
    }
    logger.info(`email ${email} is valid`);

    const passwordValidated = UserService.validatePassword(password);
    if (!passwordValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_VALID,
      });
    }
    logger.info(`password ${password} is valid`);

    const isMatch = UserService.comparePassword(password, user.password);
    if (!isMatch) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_MATCH,
      });
    }
    logger.info(`password ${password} is valid`);

    if (user.email === email) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.EMAIL_NOT_CHANGE,
      });
    }
    logger.info(`email ${email} is valid`);

    const emailCheck = await UserService.findByEmail(email);
    if (emailCheck) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.EMAIL_EXIST,
      });
    }

    const updatedUser = await UserService.updateEmail(id, email);
    if (!updatedUser) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.EMAIL_NOT_CHANGE,
      });
    }
    logger.info(`user ${user.username} updated`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.EMAIL_CHANGE_SUCCESS,
      data: {
        user: updatedUser,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export const updatePassword = async (req, res, next) =&amp;gt; {
  try {
    const {oldPassword, newPassword, confirmPassword} = req.body;
    const {id} = req.params;

    if (newPassword !== confirmPassword) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_MATCH,
      });
    }

    const user = await UserService.findById(id);
    if (!user) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`user ${user.username} found`);

    const oldPasswordValidated = UserService.validatePassword(oldPassword);
    if (!oldPasswordValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_VALID,
      });
    }
    logger.info(`password ${oldPassword} is valid`);

    const newPasswordValidated = UserService.validatePassword(newPassword);
    if (!newPasswordValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_VALID,
      });
    }
    logger.info(`password ${newPassword} is valid`);

    const confirmPasswordValidated =
      UserService.validatePassword(confirmPassword);
    if (!confirmPasswordValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_VALID,
      });
    }
    logger.info(`password ${confirmPassword} is valid`);

    if (oldPassword === newPassword) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_CHANGE,
      });
    }

    const isMatch = UserService.comparePassword(oldPassword, user.password);
    if (!isMatch) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_MATCH,
      });
    }

    const updatedUser = await UserService.updatePassword(id, newPassword);
    if (!updatedUser) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_CHANGE,
      });
    }
    logger.info(`user ${user.username} updated`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.PASSWORD_CHANGE_SUCCESS,
      data: {
        user: updatedUser,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export const updatePhone = async (req, res, next) =&amp;gt; {
  try {
    const {phone, password} = req.body;
    const {id} = req.params;

    const user = await UserService.findById(id);
    if (!user) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`user ${user.username} found`);

    const phoneValidated = UserService.validatePhone(phone);
    if (!phoneValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PHONE_NOT_VALID,
      });
    }

    const passwordValidated = UserService.validatePassword(password);
    if (!passwordValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_VALID,
      });
    }
    logger.info(`password ${password} is valid`);

    const isMatch = UserService.comparePassword(password, user.password);
    if (!isMatch) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_MATCH,
      });
    }
    logger.info(`password ${password} is valid`);

    if (user.phone === phone) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PHONE_NOT_CHANGE,
      });
    }

    const phoneCheck = await UserService.findByPhone(phone);
    if (phoneCheck) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PHONE_EXIST,
      });
    }

    const updatedUser = await UserService.updatePhone(id, phone);
    if (!updatedUser) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PHONE_NOT_CHANGE,
      });
    }
    logger.info(`user ${user.username} updated`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.PHONE_CHANGE_SUCCESS,
      data: {
        user: updatedUser,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export const updateAddress = async (req, res, next) =&amp;gt; {
  try {
    const {address, password} = req.body;
    const {id} = req.params;

    const user = await UserService.findById(id);
    if (!user) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`user ${user.username} found`);

    const addressValidated = UserService.validateAddress(address);
    if (!addressValidated) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.ADDRESS_NOT_VALID,
      });
    }

    const isMatch = UserService.comparePassword(password, user.password);
    if (!isMatch) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.PASSWORD_NOT_MATCH,
      });
    }
    logger.info(`password ${password} is valid`);

    if (user.address === address) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.ADDRESS_NOT_CHANGE,
      });
    }

    const updatedUser = await UserService.updateAddress(id, address);
    if (!updatedUser) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.ADDRESS_NOT_CHANGE,
      });
    }
    logger.info(`user ${user.username} updated`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.ADDRESS_CHANGE_SUCCESS,
      data: {
        user: updatedUser,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export const deleteUser = async (req, res, next) =&amp;gt; {
  try {
    const {id} = req.params;

    const user = await UserService.findById(id);
    if (!user) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`user ${user.username} found`);

    const deletedUser = await UserService.deleteUser(id);
    if (!deletedUser) {
      return res.status(ConstantHttpCode.BAD_REQUEST).json({
        status: {
          code: ConstantHttpCode.BAD_REQUEST,
          msg: ConstantHttpReason.BAD_REQUEST,
        },
        msg: ConstantMessage.USER_NOT_DELETE,
      });
    }
    logger.info(`user ${user.username} deleted`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.USER_DELETE_SUCCESS,
    });
  } catch (err) {
    return next(err);
  }
};

export const getUser = async (req, res, next) =&amp;gt; {
  try {
    const {id} = req.params;
    logger.info(`user ${id} found`);

    const user = await UserService.findByIdWithOutPassword(id);
    logger.info(`user ${user} found`);
    if (!user) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`user ${user.username} found`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.USER_FOUND,
      data: {
        user,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export const getUsers = async (req, res, next) =&amp;gt; {
  try {
    const users = await UserService.findAll();
    if (!users) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`users found`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.USER_FOUND,
      data: {
        users,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export const getUsersStats = async (req, res, next) =&amp;gt; {
  try {
    const usersStats = await UserService.getUsersStats();
    if (!usersStats) {
      return res.status(ConstantHttpCode.NOT_FOUND).json({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: ConstantMessage.USER_NOT_FOUND,
      });
    }
    logger.info(`users stats found`);

    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      msg: ConstantMessage.USER_FOUND,
      data: {
        users: usersStats,
      },
    });
  } catch (err) {
    return next(err);
  }
};

export default {
  updateUsername,
  updateName,
  updateEmail,
  updatePassword,
  updatePhone,
  updateAddress,
  deleteUser,
  getUser,
  getUsers,
  getUsersStats,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication Routes&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;auth.router.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import ConstantAPI from &amp;#39;../constants/api.constant&amp;#39;;
import AuthController from &amp;#39;../controllers/auth.controller&amp;#39;;
import express from &amp;#39;express&amp;#39;;

const router = express.Router();

router.post(ConstantAPI.AUTH_REGISTER, AuthController.register);
router.post(ConstantAPI.AUTH_LOGIN, AuthController.login);

export default router;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;user.router.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import ConstantAPI from &amp;#39;../constants/api.constant&amp;#39;;
import UserController from &amp;#39;../controllers/user.controller&amp;#39;;
import TokenMiddleware from &amp;#39;../middlewares/token.middleware&amp;#39;;
import express from &amp;#39;express&amp;#39;;

const router = express.Router();

router.post(
  ConstantAPI.USER_UPDATE_USERNAME,
  TokenMiddleware.verifyTokenAndAuthorization,
  UserController.updateUsername,
);
router.post(
  ConstantAPI.USER_UPDATE_NAME,
  TokenMiddleware.verifyTokenAndAuthorization,
  UserController.updateName,
);
router.post(
  ConstantAPI.USER_UPDATE_EMAIL,
  TokenMiddleware.verifyTokenAndAuthorization,
  UserController.updateEmail,
);
router.post(
  ConstantAPI.USER_UPDATE_PASSWORD,
  TokenMiddleware.verifyTokenAndAuthorization,
  UserController.updatePassword,
);
router.post(
  ConstantAPI.USER_UPDATE_PHONE,
  TokenMiddleware.verifyTokenAndAuthorization,
  UserController.updatePhone,
);
router.post(
  ConstantAPI.USER_UPDATE_ADDRESS,
  TokenMiddleware.verifyTokenAndAuthorization,
  UserController.updateAddress,
);
router.post(
  ConstantAPI.USER_DELETE,
  TokenMiddleware.verifyTokenAndAuthorization,
  UserController.deleteUser,
);
router.get(
  ConstantAPI.USER_GET,
  TokenMiddleware.verifyTokenAndAuthorization,
  UserController.getUser,
);
router.get(
  ConstantAPI.USER_GET_ALL,
  TokenMiddleware.verifyTokenAndAdmin,
  UserController.getUsers,
);
router.get(
  ConstantAPI.USER_GET_ALL_STATS,
  TokenMiddleware.verifyTokenAndAdmin,
  UserController.getUsersStats,
);

export default router;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;edit &lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import connectDb from &amp;#39;./config/db.config&amp;#39;;
// api constant
import ConstantAPI from &amp;#39;./constants/api.constant&amp;#39;;
// http constant
import ConstantHttpCode from &amp;#39;./constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;./constants/http.reason.constant&amp;#39;;
import {DATABASE_URL} from &amp;#39;./env/variable.env&amp;#39;;
// routers
import AuthRouter from &amp;#39;./routers/auth.router&amp;#39;;
import UserRouter from &amp;#39;./routers/user.router&amp;#39;;
import compression from &amp;#39;compression&amp;#39;;
import cookieParser from &amp;#39;cookie-parser&amp;#39;;
import cors from &amp;#39;cors&amp;#39;;
import express from &amp;#39;express&amp;#39;;
import helmet from &amp;#39;helmet&amp;#39;;

connectDb(DATABASE_URL);

const app = express();

// helmet
app.use(helmet());

app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(compression());
app.use(cors());
app.use(cookieParser());

app.get(&amp;#39;/&amp;#39;, (req, res, next) =&amp;gt; {
  try {
    return res.status(ConstantHttpCode.OK).json({
      status: {
        code: ConstantHttpCode.OK,
        msg: ConstantHttpReason.OK,
      },
      API: &amp;#39;Work&amp;#39;,
    });
  } catch (err) {
    return next(err);
  }
});

app.use(ConstantAPI.API_AUTH, AuthRouter);
app.use(ConstantAPI.API_USERS, UserRouter);

export default app;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;Accordion client:load title=&quot;Why use Babel for a Node.js backend at all?&quot;&gt;&lt;p&gt;Babel lets you write modern ES module syntax (&lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt;) and the latest ECMAScript features, then transpile down to JavaScript your target Node version understands. You get one consistent, future-proof syntax across the codebase and a single &lt;code&gt;pnpm build&lt;/code&gt; step that emits a deployable &lt;code&gt;build/&lt;/code&gt; directory.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Can I use npm or yarn instead of pnpm?&quot;&gt;&lt;p&gt;Yes. Every &lt;code&gt;pnpm add&lt;/code&gt; maps to &lt;code&gt;npm install&lt;/code&gt; / &lt;code&gt;yarn add&lt;/code&gt;, and the &lt;code&gt;package.json&lt;/code&gt; scripts run the same way with &lt;code&gt;npm run &amp;lt;script&amp;gt;&lt;/code&gt; or &lt;code&gt;yarn &amp;lt;script&amp;gt;&lt;/code&gt;. The &lt;code&gt;engine-strict&lt;/code&gt; setting in &lt;code&gt;.npmrc&lt;/code&gt; plus the &lt;code&gt;engines.pnpm&lt;/code&gt; field just nudge contributors toward the package manager you standardize on.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;What do the Husky hooks actually block?&quot;&gt;&lt;p&gt;The &lt;code&gt;pre-commit&lt;/code&gt; hook runs &lt;code&gt;pnpm lint&lt;/code&gt;, so a commit fails if ESLint reports errors. The &lt;code&gt;pre-push&lt;/code&gt; hook runs &lt;code&gt;pnpm build&lt;/code&gt;, so you can&amp;#39;t push code that doesn&amp;#39;t compile. The &lt;code&gt;commit-msg&lt;/code&gt; hook runs Commitlint, so commit messages must follow the conventional-commits format.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Why Winston instead of console.log?&quot;&gt;&lt;p&gt;Winston gives you log levels, multiple transports (console plus rotating files), and structured timestamps so development output stays readable while errors persist to &lt;code&gt;logs/error.log&lt;/code&gt; in production. &lt;code&gt;console.log&lt;/code&gt; can&amp;#39;t do level filtering or file output without extra work.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Is keeping the JWT secret in .env safe?&quot;&gt;&lt;p&gt;&lt;code&gt;.env&lt;/code&gt; is git-ignored, so the secret never lands in version control that&amp;#39;s the whole point of the &lt;code&gt;.env&lt;/code&gt; / &lt;code&gt;.env.example&lt;/code&gt; split. In production, inject &lt;code&gt;JWT_SECRET&lt;/code&gt; and &lt;code&gt;PASS_SECRET&lt;/code&gt; through your host&amp;#39;s environment or a secrets manager rather than a committed file.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Finally, after compilation, we can now need to deploy the compiled version in the NodeJS production server.&lt;/p&gt;
&lt;p&gt;All code from this tutorial as a complete package is available in this &lt;a href=&quot;https://github.com/MKAbuMattar/template-express&quot;&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://expressjs.com/&quot;&gt;Express.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/&quot;&gt;MongoDB Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mongoosejs.com/&quot;&gt;Mongoose ODM Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/&quot;&gt;Prettier Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://typicode.github.io/husky/&quot;&gt;Husky Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://commitlint.js.org/&quot;&gt;Commitlint Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jwt.io/&quot;&gt;JSON Web Tokens (JWT) Official Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/winstonjs/winston&quot;&gt;Winston Logger (GitHub)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/dotenv&quot;&gt;Dotenv (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/tsx&quot;&gt;tsx (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/helmet&quot;&gt;Helmet (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/crypto-js&quot;&gt;CryptoJS (Google Code Archive - for historical reference, often found on npm)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux&quot;&gt;Git SSH Keys for GitHub, GitLab, and Bitbucket on Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/dotfiles&quot;&gt;Dotfiles: A Git-Based Strategy for Configuration Management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Backend Development</category><category>Node.js</category><category>JavaScript</category><category>Development Setup</category><category>API Development</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0003-setting-up-node-js-express-mongodb-prettier-eslint-and-husky-application-with-babel-and-authentication-as-an-example/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Git SSH Keys for GitHub, GitLab, and Bitbucket on Linux</title><link>https://mkabumattar.com/blog/post/git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/</guid><description>Git connects to remotes by default via HTTPS, which requires you to enter your login and password every time you run a command like Git pull or git push, using the SSH protocol. You may connect to servers and authenticate to access their services. The three services listed allow Git to connect through SSH rather than HTTPS. Using public-key encryption eliminates the need to type a login and password for each Git command.</description><pubDate>Sun, 07 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;By default, Git talks to remotes over HTTPS, so it asks for your username and password on every &lt;code&gt;git pull&lt;/code&gt; or &lt;code&gt;git push&lt;/code&gt;. SSH fixes that. GitHub, GitLab, and Bitbucket all let Git authenticate over SSH with public-key encryption instead set it up once and you stop typing credentials for every Git command.&lt;/p&gt;
&lt;Notice type=&quot;info&quot;&gt;
  An SSH key is a pair of files: a **private key** that never leaves your
  machine, and a **public key** you upload to each service. Authentication
  happens by proving you hold the private key no password sent over the wire.
&lt;/Notice&gt;&lt;h2&gt;Make sure a Git and SSH client is installed&lt;/h2&gt;
&lt;p&gt;A Git and SSH client must be installed on your system to connect via the SSH protocol. It should be installed by default if you use Arch Linux-based distributions like Manjaro or Garuda Linux.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git --version
ssh -V
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That command should return the Git version and SSH client&amp;#39;s version number:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git version 2.34.1
OpenSSH_8.8p1, OpenSSL 1.1.1l  24 Aug 2021
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the system tells you that the &lt;code&gt;ssh&lt;/code&gt; or &lt;code&gt;git&lt;/code&gt; commands are missing, install them with the command set for your distribution:&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Arch&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo pacman -Syu
sudo pacman -Syyu
sudo pacman -S git
sudo pacman -S openssh
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Debian&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo apt update
sudo apt upgrade
sudo apt install git
sudo apt install openssh
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Red Hat&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo yum upgrade
sudo yum install git
sudo yum install openssh
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;SUSE&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo zypper upgrade
sudo zypper install git
sudo zypper install openssh
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Fedora&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo dnf upgrade
sudo dnf install git
sudo dnf install openssh
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;p&gt;Don&amp;#39;t forget to specify global Git settings using the following command after installing Git:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git config --global user.name &amp;#39;USERNAME&amp;#39;
git config --global user.email &amp;#39;YOUR_EMAIL@EXAMPLE.COM&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Look for any SSH keys that have already been created&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ls -lah ~/.ssh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That command lists the contents of the &lt;code&gt;~/.ssh&lt;/code&gt; folder, where the SSH client stores its configuration files. A typical populated directory looks like this:&lt;/p&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;~/.ssh/&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;id_ed25519&lt;/strong&gt; Ed25519 private key never share this&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;id_ed25519.pub&lt;/strong&gt; Ed25519 public key safe to upload&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;id_rsa&lt;/strong&gt; RSA private key (legacy) never share this&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;id_rsa.pub&lt;/strong&gt; RSA public key (legacy) safe to upload&lt;/li&gt;
&lt;li&gt;known_hosts&lt;/li&gt;
&lt;li&gt;config&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;Notice type=&quot;note&quot;&gt;
  Don&apos;t worry if you get an error saying there is no `~/.ssh` directory or no
  files in there it just indicates you haven&apos;t established an SSH key pair yet.
  Proceed to the next section if this is the case.
&lt;/Notice&gt;&lt;Notice type=&quot;tip&quot;&gt;
  It&apos;s worth regenerating your SSH key pair about once a year. If your current
  pair is older than that, generate a new one below; if it&apos;s recent and you want
  to keep it, skip the next section.
&lt;/Notice&gt;&lt;h2&gt;Make a fresh set of SSH keys&lt;/h2&gt;
&lt;p&gt;Generate a new SSH key pair, replacing &lt;code&gt;YOUR_EMAIL@EXAMPLE.COM&lt;/code&gt; with your email address. &lt;strong&gt;Use Ed25519&lt;/strong&gt; it&amp;#39;s what GitHub, GitLab, and Bitbucket recommend today. Reach for RSA only on an older system or server that doesn&amp;#39;t support Ed25519.&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Ed25519 (recommended)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh-keygen -t ed25519 -C &amp;#39;YOUR_EMAIL@EXAMPLE.COM&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates &lt;code&gt;~/.ssh/id_ed25519&lt;/code&gt; (private) and &lt;code&gt;~/.ssh/id_ed25519.pub&lt;/code&gt; (public). Ed25519 keys are small and fast, with security on par with a 4096-bit RSA key.&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;RSA (legacy)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh-keygen -t rsa -b 4096 -C &amp;#39;YOUR_EMAIL@EXAMPLE.COM&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates &lt;code&gt;~/.ssh/id_rsa&lt;/code&gt; (private) and &lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt; (public). Use the older RSA type only if you need to talk to a legacy system or server that doesn&amp;#39;t support Ed25519.&lt;/p&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;p&gt;After running the command, complete the prompts:&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Choose where to save the private key. Press &lt;Kbd&gt;Enter&lt;/Kbd&gt; to accept the default location (&lt;code&gt;~/.ssh/id_ed25519&lt;/code&gt;, or &lt;code&gt;~/.ssh/id_rsa&lt;/code&gt; for an RSA key):&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Generating public/private ed25519 key pair. Enter file in which to save the key (/home/your_user_name/.ssh/id_ed25519):
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;If a private key already exists, you&amp;#39;ll be asked whether to overwrite it. Type &lt;code&gt;y&lt;/code&gt; and press &lt;Kbd&gt;Enter&lt;/Kbd&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;/home/your_user_name/.ssh/id_ed25519 already exists.
Overwrite (y/n)?
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Enter and re-enter a passphrase (think of it as a password for the key):&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Enter passphrase (empty for no passphrase):
Enter same passphrase again:
&lt;/code&gt;&lt;/pre&gt;
&lt;/Steps&gt;&lt;Notice type=&quot;tip&quot;&gt;
  A passphrase encrypts your private key on disk, so a stolen key file is
  useless without it. Combined with the `ssh-agent` (next section), you only
  type it once per session.
&lt;/Notice&gt;&lt;p&gt;The SSH key pair is created in &lt;code&gt;~/.ssh&lt;/code&gt;, and the whole interaction should look like this:&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Ed25519 (recommended)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;your_user_name@your_host_name:~&amp;gt; ssh-keygen -t ed25519 -C &amp;#39;YOUR_EMAIL@EXAMPLE.COM&amp;#39;
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/YOUR_USER_NAME/.ssh/id_ed25519):
/home/YOUR_USER_NAME/.ssh/id_ed25519 already exists.
Overwrite (y/n)? y
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/YOUR_USER_NAME/.ssh/id_ed25519.
Your public key has been saved in /home/YOUR_USER_NAME/.ssh/id_ed25519.pub.
The key fingerprint is:
SHA256:Qx3yXenY8FOQmvIsjKVp6oAlITe3k1aMKRdViOFePP6 YOUR_EMAIL@EXAMPLE.COM
The key&amp;#39;s randomart image is:
+--[ED25519 256]--+
|        .o+.     |
|       .oo=o     |
|      . o*+.o    |
|     . ..oB.+    |
|      o.S=.* .   |
|     . +o.E o    |
|      o.o+.= .   |
|       =o.++o    |
|      ..o**+.    |
+----[SHA256]-----+
YOUR_USER_NAME@YOUR_HOST_NAME:~&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;RSA (legacy)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;your_user_name@your_host_name:~&amp;gt; ssh-keygen -t rsa -b 4096 -C &amp;#39;YOUR_EMAIL@EXAMPLE.COM&amp;#39;
Generating public/private rsa key pair.
Enter file in which to save the key (/home/YOUR_USER_NAME/.ssh/id_rsa):
/home/YOUR_USER_NAME/.ssh/id_rsa already exists.
Overwrite (y/n)? y
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/YOUR_USER_NAME/.ssh/id_rsa.
Your public key has been saved in /home/YOUR_USER_NAME/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:XenY8FOQmvIsjKVp6oAlITe3k1aMKRdViOFePP6/CuK YOUR_EMAIL@EXAMPLE.COM
The key&amp;#39;s randomart image is:
+---[RSA 4096]----+
|o.=@X++.         |
|o*@O++           |
|=Bo+=+           |
|Oo+ oo..         |
|=+ . .. S        |
|...   o          |
| .   o .         |
|    . . o        |
|   E   . o.      |
+----[SHA256]-----+
YOUR_USER_NAME@YOUR_HOST_NAME:~&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;h2&gt;To the ssh-agent, add your private SSH key&lt;/h2&gt;
&lt;p&gt;If you&amp;#39;d rather not retype your passphrase every time you use the key, add it to the &lt;code&gt;ssh-agent&lt;/code&gt; a background process that keeps your keys in memory while you&amp;#39;re logged in.&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Start the &lt;code&gt;ssh-agent&lt;/code&gt; in the background:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;eval &amp;quot;$(ssh-agent -s)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command returns the &lt;code&gt;ssh-agent&lt;/code&gt; process identification:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Agent pid 2887
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Add your SSH private key to the &lt;code&gt;ssh-agent&lt;/code&gt; pick the tab for your key type:&lt;/li&gt;
&lt;/ol&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Ed25519 (recommended)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh-add ~/.ssh/id_ed25519
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;RSA (legacy)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh-add ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Type your passphrase and press &lt;Kbd&gt;Enter&lt;/Kbd&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Enter passphrase for /home/YOUR_USER_NAME/.ssh/id_ed25519:
&lt;/code&gt;&lt;/pre&gt;
&lt;/Steps&gt;&lt;p&gt;The &lt;code&gt;ssh-agent&lt;/code&gt; confirms the private SSH key has been added:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Identity added: /home/YOUR_USER_NAME/.ssh/id_ed25519 (YOUR_EMAIL@EXAMPLE.COM)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;To your account, add the public SSH key&lt;/h2&gt;
&lt;p&gt;You can connect through SSH once you have an SSH key and have added it to the &lt;code&gt;ssh-agent&lt;/code&gt;. The procedure is the same for all three services: copy your public key to the clipboard, then paste it into the service&amp;#39;s SSH-keys settings.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xclip&lt;/code&gt; is a command-line tool that gives you access to the clipboard from the terminal. If it isn&amp;#39;t already installed, install it for your distribution:&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Arch&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo pacman -Syu
sudo pacman -Syyu
sudo pacman -S xclip
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Debian&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo apt update
sudo apt upgrade
sudo apt install xclip
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Red Hat&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo yum upgrade
sudo yum install xclip
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;SUSE&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo zypper upgrade
sudo zypper install xclip
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Fedora&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo dnf upgrade
sudo dnf install xclip
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;p&gt;Using the &lt;code&gt;xclip&lt;/code&gt; command, copy the contents of your public SSH key to the clipboard pick the tab that matches the key type you created:&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Ed25519 (recommended)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;xclip -sel clip &amp;lt; ~/.ssh/id_ed25519.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;RSA (legacy)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;xclip -sel clip &amp;lt; ~/.ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;Notice type=&quot;warning&quot;&gt;
  Only ever copy and paste the **public** key (the `.pub` file). The private key
  (`id_ed25519` or `id_rsa`, with no extension) must never be uploaded or shared
  with anyone.
&lt;/Notice&gt;&lt;p&gt;Now add that public key to your account. Pick your service below:&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;GitHub&quot;&gt;&lt;p&gt;Sign in to your GitHub account by going to github.com and entering your username and password. Click your profile photo in the upper-right corner of the page, then &lt;strong&gt;Settings&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/github1.png&quot; alt=&quot;GitHub Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;Select &lt;strong&gt;SSH and GPG keys&lt;/strong&gt; from the user settings sidebar, then select &lt;strong&gt;New SSH key&lt;/strong&gt;. Put a descriptive label for the new key in the Title area (for example, your computer&amp;#39;s name) and paste your public key into the Key field. Finally, click &lt;strong&gt;Add SSH key&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/github2.png&quot; alt=&quot;GitHub Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;The key is now visible in the list of SSH keys linked to your account:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/github3.png&quot; alt=&quot;GitHub Settings&quot;&gt;&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;GitLab&quot;&gt;&lt;p&gt;Sign in to your GitLab account by going to gitlab.com and entering your username and password. Click your profile photo in the upper-right corner of the page, then &lt;strong&gt;Settings&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/gitlab1.png&quot; alt=&quot;GitLab Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;SSH Keys&lt;/strong&gt; in the User Settings sidebar. In the Key area, paste your public key. Fill in the Title field with a descriptive term (for example, the name of your computer). Finally, click &lt;strong&gt;Add key&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/gitlab2.png&quot; alt=&quot;GitLab Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;The key is now visible in the list of SSH keys linked to your account:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/gitlab3.png&quot; alt=&quot;GitLab Settings&quot;&gt;&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Bitbucket&quot;&gt;&lt;p&gt;Log in to your Bitbucket account by going to bitbucket.org and entering your username and password. Click your profile photo in the lower-left corner of the website, then &lt;strong&gt;Bitbucket settings&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/bitbucket1.png&quot; alt=&quot;Bitbucket Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;SSH keys may be found in the Settings sidebar&amp;#39;s &lt;strong&gt;Security&lt;/strong&gt; section. After that, select &lt;strong&gt;Add key&lt;/strong&gt;. Fill the Description box with a descriptive label for the new key (such as your computer&amp;#39;s name), then paste your public key into the Key field. Finally, choose &lt;strong&gt;Add key&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/bitbucket2.png&quot; alt=&quot;Bitbucket Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;The key has now been added to your account&amp;#39;s list of SSH keys:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/bitbucket3.png&quot; alt=&quot;Bitbucket Settings&quot;&gt;&lt;/p&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;h2&gt;Test connecting via SSH&lt;/h2&gt;
&lt;p&gt;Before you start using SSH with Git, all three services let you check that the connection works.&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;GitHub&quot;&gt;&lt;p&gt;Once you&amp;#39;ve added your SSH key to your GitHub account, open the terminal and type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -T git@github.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;#39;re connecting to GitHub over SSH for the first time, the SSH client will ask if you trust the GitHub server&amp;#39;s public key:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;The authenticity of host &amp;#39;github.com (140.82.113.4)&amp;#39; can&amp;#39;t be established.
RSA key fingerprint is SHA256:a5d6c20b1790b4c144b9d26c9b201bbee3797aa010f2701c09c1b3a6262d2c02.
Are you sure you want to continue connecting (yes/no)?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Type &lt;code&gt;yes&lt;/code&gt; and press &lt;Kbd&gt;Enter&lt;/Kbd&gt;. GitHub is added to the list of trustworthy hosts in the SSH client, and you won&amp;#39;t be asked about its public key again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Warning: Permanently added &amp;#39;github.com,140.82.113.4&amp;#39; (RSA) to the list of known hosts.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GitHub only allows this SSH connection for testing, not shell access, so it confirms you&amp;#39;re authenticated and then closes the connection:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Hi YOUR_USER_NAME! You&amp;#39;ve successfully authenticated, but GitHub does not provide shell access.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The entire interaction should look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -T git@github.com

The authenticity of host &amp;#39;github.com (140.82.113.4)&amp;#39; can&amp;#39;t be established.
RSA key fingerprint is SHA256:a5d6c20b1790b4c144b9d26c9b201bbee3797aa010f2701c09c1b3a6262d2c02.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added &amp;#39;github.com,140.82.113.4&amp;#39; (RSA) to the list of known hosts.
Hi your_user_name! You&amp;#39;ve successfully authenticated, but GitHub does not provide shell access.
YOUR_USER_NAME@YOUR_HOST_NAME:~&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test passed you&amp;#39;re ready to use SSH with GitHub.&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;GitLab&quot;&gt;&lt;p&gt;Once you&amp;#39;ve added your SSH key to your GitLab account, the test is pretty similar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -T git@gitlab.com

The authenticity of host &amp;#39;gitlab.com (35.231.145.151)&amp;#39; can&amp;#39;t be established.
ECDSA key fingerprint is SHA256:4ac7a7fd4296d5e6267c9188346375ff78f6097a802e83c0feaf25277c9e70cc.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added &amp;#39;gitlab.com,35.231.145.151&amp;#39; (ECDSA) to the list of known hosts.
Welcome to GitLab, @YOUR_USER_NAME!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test passed you&amp;#39;re ready to use SSH with GitLab.&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Bitbucket&quot;&gt;&lt;p&gt;Once you&amp;#39;ve added your SSH key to your Bitbucket account, the test is pretty similar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -T git@bitbucket.org

The authenticity of host &amp;#39;bitbucket.org (104.192.143.1)&amp;#39; can&amp;#39;t be established.
RSA key fingerprint is SHA256:fb7d37d5497c43f73325e0a98638cac8dda3b01a8c31f4ee11e2e953c19e0252.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added &amp;#39;bitbucket.org,104.192.143.1&amp;#39; (RSA) to the list of known hosts.
logged in as YOUR_USER_NAME.

You can use git or hg to connect to Bitbucket. Shell access is disabled.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test passed you&amp;#39;re ready to use SSH with Bitbucket.&lt;/p&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;Accordion client:load title=&quot;Should I set a passphrase on my SSH key?&quot;&gt;&lt;p&gt;Yes. A passphrase encrypts the private key on disk, so if the file is ever stolen it&amp;#39;s useless without the passphrase. Pair it with the &lt;code&gt;ssh-agent&lt;/code&gt; so you only type it once per login session rather than on every Git command.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;RSA or Ed25519 which key type should I use?&quot;&gt;&lt;p&gt;Use &lt;code&gt;ed25519&lt;/code&gt;. The keys are smaller and faster than RSA with comparable security, and it&amp;#39;s what GitHub, GitLab, and Bitbucket recommend. Generate one with &lt;code&gt;ssh-keygen -t ed25519 -C &amp;#39;YOUR_EMAIL@EXAMPLE.COM&amp;#39;&lt;/code&gt;. Reach for &lt;code&gt;rsa -b 4096&lt;/code&gt; only when you need to connect to an older server that doesn&amp;#39;t speak Ed25519.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Can I use the same key for GitHub, GitLab, and Bitbucket?&quot;&gt;&lt;p&gt;Yes. The same &lt;strong&gt;public&lt;/strong&gt; key can be added to as many accounts and services as you like there&amp;#39;s no need for a separate key per provider. Just paste &lt;code&gt;~/.ssh/id_ed25519.pub&lt;/code&gt; (or &lt;code&gt;id_rsa.pub&lt;/code&gt;) into each service&amp;#39;s SSH-keys settings.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;I get &apos;Permission denied (publickey)&apos; what&apos;s wrong?&quot;&gt;&lt;p&gt;Usually one of: the key wasn&amp;#39;t added to the &lt;code&gt;ssh-agent&lt;/code&gt; (&lt;code&gt;ssh-add ~/.ssh/id_ed25519&lt;/code&gt;), the public key wasn&amp;#39;t added to the service, or the wrong key path is being used. Run &lt;code&gt;ssh -vT git@github.com&lt;/code&gt; to see which key the client offers, and confirm &lt;code&gt;~/.ssh&lt;/code&gt; permissions are &lt;code&gt;700&lt;/code&gt; and the private key is &lt;code&gt;600&lt;/code&gt;.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Why is my passphrase requested every time?&quot;&gt;&lt;p&gt;The &lt;code&gt;ssh-agent&lt;/code&gt; isn&amp;#39;t running or isn&amp;#39;t persisting between sessions. Start it with &lt;code&gt;eval &amp;quot;$(ssh-agent -s)&amp;quot;&lt;/code&gt; and add the key with &lt;code&gt;ssh-add&lt;/code&gt;. To make it stick automatically, add &lt;code&gt;AddKeysToAgent yes&lt;/code&gt; (and optionally &lt;code&gt;UseKeychain yes&lt;/code&gt; on macOS) under your host in &lt;code&gt;~/.ssh/config&lt;/code&gt;.&lt;/p&gt;
&lt;/Accordion&gt;&lt;hr&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent&quot;&gt;GitHub Docs: Generating a new SSH key and adding it to the ssh-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account&quot;&gt;GitHub Docs: Adding a new SSH key to your GitHub account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/working-with-ssh-key-passphrases&quot;&gt;GitHub Docs: Working with SSH key passphrases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/user/ssh.html&quot;&gt;GitLab Docs: Use SSH keys to communicate with GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.atlassian.com/bitbucket-cloud/docs/set-up-an-ssh-key/&quot;&gt;Bitbucket Docs: Set up an SSH key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.openssh.com/&quot;&gt;OpenSSH Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man.openbsd.org/ssh-keygen.1&quot;&gt;&lt;code&gt;ssh-keygen&lt;/code&gt; man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man.openbsd.org/ssh-agent.1&quot;&gt;&lt;code&gt;ssh-agent&lt;/code&gt; man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man.openbsd.org/ssh-add.1&quot;&gt;&lt;code&gt;ssh-add&lt;/code&gt; man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/SSH_keys&quot;&gt;ArchWiki: SSH keys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-2&quot;&gt;DigitalOcean: How To Set Up SSH Keys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key&quot;&gt;Git SCM Book: Git on the Server - Generating Your SSH Public Key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linux.die.net/man/1/xclip&quot;&gt;xclip man page (or alternative like xsel)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ssh.com/academy/ssh&quot;&gt;SSH (Secure Shell) Protocol Overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Linux</category><category>Git</category><category>SSH</category><category>Version Control</category><category>Developer Tools</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0001-git-ssh-keys-for-github-gitlab-and-bitbucket-on-linux/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Git SSH Keys for GitHub, GitLab, and Bitbucket on Windows</title><link>https://mkabumattar.com/blog/post/git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/</guid><description>Git connects to remotes by default via HTTPS, which requires you to enter your login and password every time you run a command like Git pull or git push, using the SSH protocol. You may connect to servers and authenticate to access their services. The three services listed allow Git to connect through SSH rather than HTTPS. Using public-key encryption eliminates the need to type a login and password for each Git command.</description><pubDate>Sun, 07 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;By default, Git talks to remotes over HTTPS, so it asks for your username and password on every &lt;code&gt;git pull&lt;/code&gt; or &lt;code&gt;git push&lt;/code&gt;. SSH fixes that. GitHub, GitLab, and Bitbucket all let Git authenticate over SSH with public-key encryption instead. Set it up once and you stop typing credentials for every Git command.&lt;/p&gt;
&lt;Notice type=&quot;info&quot;&gt;
  An SSH key is a pair of files: a **private key** that never leaves your
  machine, and a **public key** you upload to each service. Authentication works
  by proving you hold the private key. No password travels over the network.
&lt;/Notice&gt;&lt;h2&gt;Make sure Git is installed&lt;/h2&gt;
&lt;p&gt;Before you start, check whether Git is already on your machine. Run this in Windows Terminal (or PowerShell):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;git --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you get a version number back, you&amp;#39;re set skip to &lt;a href=&quot;#generate-ssh-keys&quot;&gt;Generate SSH keys&lt;/a&gt;. If the command isn&amp;#39;t found, install Git using whichever method you prefer.&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Official installer&quot;&gt;&lt;ol&gt;
&lt;li&gt;Download the latest &lt;strong&gt;Git for Windows&lt;/strong&gt; from the official site.&lt;/li&gt;
&lt;li&gt;Run the installer. The defaults are sensible clicking &lt;strong&gt;Next&lt;/strong&gt; through each screen is fine for most setups, including the editor, line-ending, and terminal choices.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;, then &lt;strong&gt;Finish&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open a new terminal and confirm it worked:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;git --version
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Chocolatey&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;choco install git -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then confirm the install:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;git --version
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Winget&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;winget install --id Git.Git -e
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then confirm the install:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;git --version
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;Notice type=&quot;note&quot;&gt;
  After installing Git, set your global name and email every commit you make is
  stamped with them:
&lt;/Notice&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;git config --global user.name &amp;#39;USERNAME&amp;#39;
git config --global user.email &amp;#39;YOUR_EMAIL@EXAMPLE.COM&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Generate SSH keys&lt;/h2&gt;
&lt;p&gt;Open Windows Terminal and generate a new key pair, replacing &lt;code&gt;YOUR_EMAIL@EXAMPLE.COM&lt;/code&gt; with your email address. &lt;strong&gt;Use Ed25519&lt;/strong&gt; it&amp;#39;s what GitHub, GitLab, and Bitbucket recommend today. Reach for RSA only on an older system or server that doesn&amp;#39;t support Ed25519.&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Ed25519 (recommended)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;ssh-keygen -t ed25519 -C &amp;quot;YOUR_EMAIL@EXAMPLE.COM&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates &lt;code&gt;.ssh\id_ed25519&lt;/code&gt; (private) and &lt;code&gt;.ssh\id_ed25519.pub&lt;/code&gt; (public) in your user folder. Ed25519 keys are small and fast, with security on par with a 4096-bit RSA key.&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;RSA (legacy)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;ssh-keygen -t rsa -b 4096 -C &amp;quot;YOUR_EMAIL@EXAMPLE.COM&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates &lt;code&gt;.ssh\id_rsa&lt;/code&gt; (private) and &lt;code&gt;.ssh\id_rsa.pub&lt;/code&gt; (public). Use the older RSA type only if you need to talk to a legacy system or server that doesn&amp;#39;t support Ed25519.&lt;/p&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;p&gt;After running the command, complete the prompts:&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;Choose where to save the private key. Press &lt;Kbd&gt;Enter&lt;/Kbd&gt; to accept the default location (&lt;code&gt;C:\Users\you\.ssh\id_ed25519&lt;/code&gt;, or &lt;code&gt;id_rsa&lt;/code&gt; for an RSA key):&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Enter file in which to save the key (/c/Users/you/.ssh/id_ed25519): [Press Enter]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;If a key already exists, you&amp;#39;ll be asked whether to overwrite it. Type &lt;code&gt;y&lt;/code&gt; and press &lt;Kbd&gt;Enter&lt;/Kbd&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Overwrite (y/n)?
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Enter and re-enter a passphrase (think of it as a password for the key):&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Enter passphrase (empty for no passphrase): [Type a passphrase]
Enter same passphrase again: [Type passphrase again]
&lt;/code&gt;&lt;/pre&gt;
&lt;/Steps&gt;&lt;Notice type=&quot;tip&quot;&gt;
  A passphrase encrypts your private key on disk, so a stolen key file is
  useless without it. On Windows you can have the OpenSSH Authentication Agent
  remember it for you (see the FAQ below) so you only type it once.
&lt;/Notice&gt;&lt;p&gt;The whole interaction should look like this:&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Ed25519 (recommended)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Generating public/private ed25519 key pair.
Enter file in which to save the key (/c/Users/you/.ssh/id_ed25519):
Created directory &amp;#39;/c/Users/you/.ssh&amp;#39;.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/you/.ssh/id_ed25519.
Your public key has been saved in /c/Users/you/.ssh/id_ed25519.pub.
The key fingerprint is:
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx YOUR_EMAIL@EXAMPLE.COM
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;RSA (legacy)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/you/.ssh/id_rsa):
Created directory &amp;#39;/c/Users/you/.ssh&amp;#39;.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/you/.ssh/id_rsa.
Your public key has been saved in /c/Users/you/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx YOUR_EMAIL@EXAMPLE.COM
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;p&gt;Confirm the key landed in your &lt;code&gt;.ssh&lt;/code&gt; folder:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Get-ChildItem .\.ssh\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A typical &lt;code&gt;.ssh&lt;/code&gt; folder looks like this:&lt;/p&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;.ssh/&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;id_ed25519&lt;/strong&gt; Ed25519 private key never share this&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;id_ed25519.pub&lt;/strong&gt; Ed25519 public key safe to upload&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;id_rsa&lt;/strong&gt; RSA private key (legacy) never share this&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;id_rsa.pub&lt;/strong&gt; RSA public key (legacy) safe to upload&lt;/li&gt;
&lt;li&gt;known_hosts&lt;/li&gt;
&lt;li&gt;config&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;h2&gt;Add the public SSH key to your account&lt;/h2&gt;
&lt;p&gt;Copy your public key to the clipboard with PowerShell pick the tab that matches the key type you created:&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;Ed25519 (recommended)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Get-Content .\.ssh\id_ed25519.pub | Set-Clipboard
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;RSA (legacy)&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Get-Content .\.ssh\id_rsa.pub | Set-Clipboard
&lt;/code&gt;&lt;/pre&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;Notice type=&quot;warning&quot;&gt;
  Only ever copy and paste the **public** key (the `.pub` file). The private key
  (`id_ed25519` or `id_rsa`, with no extension) must never be uploaded or shared
  with anyone.
&lt;/Notice&gt;&lt;p&gt;Now add that public key to your account. Pick your service below:&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;GitHub&quot;&gt;&lt;p&gt;Sign in to your GitHub account at github.com. Click your profile photo in the upper-right corner, then &lt;strong&gt;Settings&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/github1.png&quot; alt=&quot;GitHub Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;Select &lt;strong&gt;SSH and GPG keys&lt;/strong&gt; from the sidebar, then &lt;strong&gt;New SSH key&lt;/strong&gt;. Give it a descriptive title (for example, your computer&amp;#39;s name) and paste your public key into the Key field. Click &lt;strong&gt;Add SSH key&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/github2.png&quot; alt=&quot;GitHub Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;The key now appears in the list of SSH keys on your account:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/github3.png&quot; alt=&quot;GitHub Settings&quot;&gt;&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;GitLab&quot;&gt;&lt;p&gt;Sign in to your GitLab account at gitlab.com. Click your profile photo in the upper-right corner, then &lt;strong&gt;Settings&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/gitlab1.png&quot; alt=&quot;GitLab Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;SSH Keys&lt;/strong&gt; in the sidebar and paste your public key into the Key field. Add a descriptive title (for example, the name of your computer), then click &lt;strong&gt;Add key&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/gitlab2.png&quot; alt=&quot;GitLab Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;The key now appears in the list of SSH keys on your account:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/gitlab3.png&quot; alt=&quot;GitLab Settings&quot;&gt;&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Bitbucket&quot;&gt;&lt;p&gt;Log in to your Bitbucket account at bitbucket.org. Click your profile photo in the lower-left corner, then &lt;strong&gt;Bitbucket settings&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/bitbucket1.png&quot; alt=&quot;Bitbucket Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;Find &lt;strong&gt;SSH keys&lt;/strong&gt; under the Security section, then select &lt;strong&gt;Add key&lt;/strong&gt;. Add a descriptive label (such as your computer&amp;#39;s name) and paste your public key into the Key field. Click &lt;strong&gt;Add key&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/bitbucket2.png&quot; alt=&quot;Bitbucket Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;The key has now been added to your account&amp;#39;s list of SSH keys:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/bitbucket3.png&quot; alt=&quot;Bitbucket Settings&quot;&gt;&lt;/p&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;h2&gt;Test connecting via SSH&lt;/h2&gt;
&lt;p&gt;Before you start using SSH with Git, all three services let you check that the connection works.&lt;/p&gt;
&lt;Tabs&gt;&lt;Tab name=&quot;GitHub&quot;&gt;&lt;p&gt;Once you&amp;#39;ve added your SSH key to your GitHub account, open the terminal and type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -T git@github.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;#39;re connecting to GitHub over SSH for the first time, the SSH client will ask if you trust the GitHub server&amp;#39;s public key:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;The authenticity of host &amp;#39;github.com (140.82.113.4)&amp;#39; can&amp;#39;t be established.
RSA key fingerprint is SHA256:a5d6c20b1790b4c144b9d26c9b201bbee3797aa010f2701c09c1b3a6262d2c02.
Are you sure you want to continue connecting (yes/no)?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Type &lt;code&gt;yes&lt;/code&gt; and press &lt;Kbd&gt;Enter&lt;/Kbd&gt;. GitHub is added to your known hosts and won&amp;#39;t prompt again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Warning: Permanently added &amp;#39;github.com,140.82.113.4&amp;#39; (RSA) to the list of known hosts.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GitHub only allows this SSH connection for testing, not shell access, so it confirms you&amp;#39;re authenticated and then closes the connection:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Hi YOUR_USER_NAME! You&amp;#39;ve successfully authenticated, but GitHub does not provide shell access.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The whole interaction should look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -T git@github.com

The authenticity of host &amp;#39;github.com (140.82.113.4)&amp;#39; can&amp;#39;t be established.
RSA key fingerprint is SHA256:a5d6c20b1790b4c144b9d26c9b201bbee3797aa010f2701c09c1b3a6262d2c02.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added &amp;#39;github.com,140.82.113.4&amp;#39; (RSA) to the list of known hosts.
Hi your_user_name! You&amp;#39;ve successfully authenticated, but GitHub does not provide shell access.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test passed you&amp;#39;re ready to use SSH with GitHub.&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;GitLab&quot;&gt;&lt;p&gt;Once you&amp;#39;ve added your SSH key to your GitLab account, the test is pretty similar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -T git@gitlab.com

The authenticity of host &amp;#39;gitlab.com (35.231.145.151)&amp;#39; can&amp;#39;t be established.
ECDSA key fingerprint is SHA256:4ac7a7fd4296d5e6267c9188346375ff78f6097a802e83c0feaf25277c9e70cc.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added &amp;#39;gitlab.com,35.231.145.151&amp;#39; (ECDSA) to the list of known hosts.
Welcome to GitLab, @YOUR_USER_NAME!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test passed you&amp;#39;re ready to use SSH with GitLab.&lt;/p&gt;
&lt;/Tab&gt;&lt;Tab name=&quot;Bitbucket&quot;&gt;&lt;p&gt;Once you&amp;#39;ve added your SSH key to your Bitbucket account, the test is pretty similar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -T git@bitbucket.org

The authenticity of host &amp;#39;bitbucket.org (104.192.143.1)&amp;#39; can&amp;#39;t be established.
RSA key fingerprint is SHA256:fb7d37d5497c43f73325e0a98638cac8dda3b01a8c31f4ee11e2e953c19e0252.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added &amp;#39;bitbucket.org,104.192.143.1&amp;#39; (RSA) to the list of known hosts.
logged in as YOUR_USER_NAME.

You can use git or hg to connect to Bitbucket. Shell access is disabled.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test passed you&amp;#39;re ready to use SSH with Bitbucket.&lt;/p&gt;
&lt;/Tab&gt;&lt;/Tabs&gt;&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;Accordion client:load title=&quot;How do I stop Windows asking for my passphrase every time?&quot;&gt;&lt;p&gt;Use the built-in OpenSSH Authentication Agent. In an &lt;strong&gt;admin&lt;/strong&gt; PowerShell, enable and start the service, then add your key:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $HOME\.ssh\id_ed25519
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The agent keeps the decrypted key in memory, so you type the passphrase once per login instead of on every Git command.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;RSA or Ed25519 which key type should I use?&quot;&gt;&lt;p&gt;Use &lt;code&gt;ed25519&lt;/code&gt;. The keys are smaller and faster than RSA with comparable security, and it&amp;#39;s what GitHub, GitLab, and Bitbucket recommend. Generate one with &lt;code&gt;ssh-keygen -t ed25519 -C &amp;quot;YOUR_EMAIL@EXAMPLE.COM&amp;quot;&lt;/code&gt;. Reach for &lt;code&gt;rsa -b 4096&lt;/code&gt; only when you need to connect to an older server that doesn&amp;#39;t speak Ed25519.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Can I use the same key for GitHub, GitLab, and Bitbucket?&quot;&gt;&lt;p&gt;Yes. The same &lt;strong&gt;public&lt;/strong&gt; key can be added to as many accounts and services as you like there&amp;#39;s no need for a separate key per provider. Just paste &lt;code&gt;id_ed25519.pub&lt;/code&gt; (or &lt;code&gt;id_rsa.pub&lt;/code&gt;) into each service&amp;#39;s SSH-keys settings.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;I get &apos;Permission denied (publickey)&apos; what&apos;s wrong?&quot;&gt;&lt;p&gt;Usually the key isn&amp;#39;t loaded in the agent, the public key wasn&amp;#39;t added to the service, or the wrong key path is being used. Run &lt;code&gt;ssh -vT git@github.com&lt;/code&gt; to see which key the client offers, confirm the OpenSSH agent is running, and make sure you uploaded the matching &lt;code&gt;.pub&lt;/code&gt; file.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;ssh or ssh-keygen isn&apos;t recognized in PowerShell. Now what?&quot;&gt;&lt;p&gt;The OpenSSH client ships with Windows 10/11 but can be disabled. Install it from an &lt;strong&gt;admin&lt;/strong&gt; PowerShell:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Git for Windows also bundles &lt;code&gt;ssh&lt;/code&gt;/&lt;code&gt;ssh-keygen&lt;/code&gt;, so running the commands inside &lt;strong&gt;Git Bash&lt;/strong&gt; works too.&lt;/p&gt;
&lt;/Accordion&gt;&lt;hr&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/downloads&quot;&gt;Git Official Website - Downloads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key&quot;&gt;Pro Git Book - Generating Your SSH Public Key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent&quot;&gt;GitHub Docs - Generating a new SSH key and adding it to the ssh-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account&quot;&gt;GitHub Docs - Adding a new SSH key to your GitHub account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/working-with-ssh-key-passphrases&quot;&gt;GitHub Docs - Working with SSH key passphrases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection&quot;&gt;GitHub Docs - Testing your SSH connection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/user/ssh.html&quot;&gt;GitLab Docs - Use SSH keys to communicate with GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.atlassian.com/bitbucket-cloud/docs/set-up-an-ssh-key/&quot;&gt;Bitbucket Docs - Set up an SSH key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement&quot;&gt;Microsoft Docs - OpenSSH key management for Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse&quot;&gt;Microsoft Docs - Get started with OpenSSH for Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://community.chocolatey.org/packages/git&quot;&gt;Chocolatey - Git Package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/winget-pkgs/tree/master/manifests/g/Git/Git&quot;&gt;Winget - Git Package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-clipboard&quot;&gt;PowerShell Set-Clipboard Cmdlet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Git</category><category>SSH</category><category>Windows</category><category>Version Control</category><category>Security</category><category>Developer Tools</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0010-git-ssh-keys-for-github-gitlab-and-bitbucket-on-windows/hero.jpg" length="0" type="image/jpeg"/></item><item><title>AI is Not Real: A Software Engineering Perspective</title><link>https://mkabumattar.com/blog/post/ai-is-not-real/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/ai-is-not-real/</guid><description>Modern AI is not intelligent in the human sense. It is large-scale statistical pattern matching and mathematical optimization. Here is what that means for the systems we build, why probabilistic chains fail, and how hybrid architectures make them reliable.</description><pubDate>Sat, 30 May 2026 02:37:09 GMT</pubDate><content:encoded>&lt;p&gt;We have all seen the wave of hype around artificial intelligence. It is everywhere, from tech conferences to science fiction scripts. As software engineers, though, we need to look past the marketing and understand what this technology actually is, and what it is not.&lt;/p&gt;
&lt;p&gt;From a systems perspective, the claim that AI is &amp;quot;intelligent&amp;quot; the way a human is misses the mark. The systems we label as AI today do not have comprehension, self-awareness, or context-driven judgment. They are very good statistical pattern matchers and optimization engines running over huge datasets.&lt;/p&gt;
&lt;p&gt;If we want to build software that is robust, scalable, and safe, we have to evaluate the underlying math, the computational limits, and the messy real-world realities of machine learning. So let&amp;#39;s walk through the gap between algorithmic learning and natural intelligence, the structural limits of language models, a few real failures, and the hybrid architectures that move us from fragile prompt engineering toward reliable computation.&lt;/p&gt;
&lt;h2&gt;Real Cognition vs. Statistical Automation&lt;/h2&gt;
&lt;p&gt;At the heart of the &amp;quot;AI is not real&amp;quot; argument is a genuine divide: biological cognition on one side, statistical automation on the other. Real intelligence shows up in natural environments and comes with understanding, reasoning, and consciousness. What we call AI today is sophisticated processing and pattern matching, and that is a different category of thing.&lt;/p&gt;
&lt;p&gt;Stephen Downes puts it well: intelligence is not a physical object. It is a property, a capacity to respond to some criterion of success. A biological brain runs a persistent, self-recursive state. Even when you are lying on the couch with your mind blank, your brain keeps running and updating its internal model of the world.&lt;/p&gt;
&lt;p&gt;A language model does none of that. It sits completely static until you send a query. Once it emits the final token, it freezes again. Its &amp;quot;personality&amp;quot; is just a temporary configuration spun up on the fly from your prompt and then thrown away.&lt;/p&gt;
&lt;p&gt;This is a long way from the symbolic logic and expert systems of the 1970s and 1980s, where programmers tried to encode intelligence as explicit rules and giant fact databases. Today we trade that explicit reasoning for statistical approximation, and in return we get something far broader and more scalable.&lt;/p&gt;
&lt;h2&gt;AI, Machine Learning, and Cognitive Computing Are Not the Same Thing&lt;/h2&gt;
&lt;p&gt;To build good systems you have to keep the terms straight. Marketing uses them interchangeably, but their goals and methods are different.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Artificial Intelligence&lt;/th&gt;
&lt;th&gt;Machine Learning&lt;/th&gt;
&lt;th&gt;Cognitive Computing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Primary objective&lt;/td&gt;
&lt;td&gt;Mimics cognitive functions to solve tasks on its own&lt;/td&gt;
&lt;td&gt;Learns from data to make predictions more accurate&lt;/td&gt;
&lt;td&gt;Simulates human thought to help people decide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System scope&lt;/td&gt;
&lt;td&gt;A broad field: robotics, NLP, decision trees&lt;/td&gt;
&lt;td&gt;A subset focused on patterns and statistical models&lt;/td&gt;
&lt;td&gt;A hybrid blending machine learning with human interaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data requirements&lt;/td&gt;
&lt;td&gt;Structured, unstructured, or programmatic rules&lt;/td&gt;
&lt;td&gt;Depends heavily on large, high-quality datasets&lt;/td&gt;
&lt;td&gt;Processes complex, messy, contextual data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution method&lt;/td&gt;
&lt;td&gt;Algorithmic logic, decision trees, neural networks&lt;/td&gt;
&lt;td&gt;Statistical models that spot patterns without coding&lt;/td&gt;
&lt;td&gt;Iterative, stateful, contextual dialogue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human interaction&lt;/td&gt;
&lt;td&gt;Acts autonomously as the maker of its own decisions&lt;/td&gt;
&lt;td&gt;Runs as an automated tool with minimal runtime input&lt;/td&gt;
&lt;td&gt;Acts as a partner, leaving the final call to the human&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;To see how we got here, look at the jump from early statistical tools to modern deep learning. Older models like Word2Vec and GloVe mapped words to static vectors. They were decent pattern matchers, but they struggled with words that have multiple meanings or depend on context. Transformers fixed this by computing each word&amp;#39;s representation dynamically, based on the surrounding tokens in the active context window.&lt;/p&gt;
&lt;h2&gt;What&amp;#39;s Actually Happening: Compression, Attention, and Emergent Behavior&lt;/h2&gt;
&lt;p&gt;Underneath the fluent output, a transformer is math, not biology. Some researchers argue that pattern compression, finding the structural shortcuts that minimize Kolmogorov complexity, is functionally close to semantic understanding. The model tunes its parameters to compress the information space so it can predict the most likely next token.&lt;/p&gt;
&lt;p&gt;The engine behind this is self-attention, which measures how the tokens in a sequence relate to one another. For every input token, the model computes a Query, a Key, and a Value vector using learned weights, then combines them:&lt;/p&gt;
&lt;p&gt;&lt;Math
  display
  math=&quot;\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V&quot;
/&gt;&lt;/p&gt;
&lt;p&gt;This lets the model weigh how much attention to pay to every other word in the sentence relative to the current one, building context on the fly. Here is a small, clean NumPy version of that formula:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import numpy as np


def self_attention(Q, K, V):
    &amp;quot;&amp;quot;&amp;quot;
    Weights the relationships between tokens.
    Q, K, V are the Query, Key, and Value matrices.
    &amp;quot;&amp;quot;&amp;quot;
    # Dimension of the key vectors, used for scaling
    d_k = K.shape[-1]

    # Raw similarity scores between Queries and Keys
    scores = np.matmul(Q, K.T) / np.sqrt(d_k)

    # Softmax turns the scores into probabilities (weights)
    weights = np.exp(scores) / np.sum(np.exp(scores), axis=-1, keepdims=True)

    # Weighted sum of the Values gives the contextual representation
    return np.matmul(weights, V)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At scale, these models pick up surprising abilities, like learning from a handful of examples or solving analogies. In one study, researchers trained a small transformer to do nothing but predict the next move in Othello game logs. The model spontaneously built a two-dimensional map of the 8x8 board inside its activations. Next-token prediction, it turns out, can produce latent representations of physical structure.&lt;/p&gt;
&lt;Notice type=&quot;info&quot;&gt;
  Emergent behavior is real and genuinely useful, but it is not evidence of
  understanding. The Othello model &quot;knows&quot; the board the way a compressed file
  &quot;knows&quot; the original: as a statistical reconstruction, not a lived concept.
&lt;/Notice&gt;&lt;h2&gt;The Hard Limits of Next-Token Prediction&lt;/h2&gt;
&lt;p&gt;For all their fluency, these models are boxed in by how they are trained. They predict the next token, which is a long way from understanding.&lt;/p&gt;
&lt;h3&gt;The Stochastic Parrot and the Gap Between Form and Meaning&lt;/h3&gt;
&lt;p&gt;The &amp;quot;stochastic parrot&amp;quot; warning is the relevant one here: it is easy to mistake fluent text for human-like comprehension. These systems learn the &lt;em&gt;form&lt;/em&gt; of language, the visible words, syntax, and characters, but they have no access to &lt;em&gt;meaning&lt;/em&gt;, the link between language and real communicative intent. You and I connect words to physical experience. A language model only connects words to other words, based on how often they appeared together in training.&lt;/p&gt;
&lt;p&gt;Emily Bender and Alexander Koller made this concrete with the Octopus Test. Picture two people, A and B, stranded on separate islands, talking over an underwater telegraph cable. A clever octopus, O, taps the line and listens. Over time it learns the statistical patterns of how B answers A, and starts impersonating B. For small talk, it works fine.&lt;/p&gt;
&lt;p&gt;Then A gets chased by a bear, grabs some sticks, and sends: &amp;quot;Help me figure out how to defend myself with these sticks.&amp;quot; The octopus is stuck. It has no body, no physical experience, and no idea what a &amp;quot;bear&amp;quot; or a &amp;quot;stick&amp;quot; is. All it can do is emit high-probability, generic text that does nothing to solve the actual crisis. That is the gap between form and meaning, laid bare.&lt;/p&gt;
&lt;h3&gt;The Reversal Curse and Conceptual Binding&lt;/h3&gt;
&lt;p&gt;Another side effect of next-token training is the Reversal Curse. Because causal language models are optimized to predict left to right, they store facts as one-way probabilities. If a model learns that &amp;quot;Mary Lee Pfeiffer is the mother of Tom Cruise,&amp;quot; it does not automatically know that &amp;quot;Tom Cruise is the son of Mary Lee Pfeiffer.&amp;quot;&lt;/p&gt;
&lt;p&gt;In a database you can query a relationship in either direction. In an autoregressive model, the fact is bound to its position in the sequence. Cognitive scientists call this a binding problem. Researchers are exploring fixes like Bidirectional Context Optimization (BICO) and Joint-Embedding Predictive Architectures (JEPA), often paired with sparse memory layers, to decouple concepts from strict sequence order.&lt;/p&gt;
&lt;p&gt;Traditional code sidesteps the whole issue with a symmetric mapping, which is something a standard autoregressive model cannot do natively:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;class SymmetricKnowledgeBase:
    &amp;quot;&amp;quot;&amp;quot;
    A lookup that avoids the Reversal Curse by mapping
    relationships symmetrically in both directions.
    &amp;quot;&amp;quot;&amp;quot;

    def __init__(self):
        self.facts = {}
        self.reverse_facts = {}

    def record_fact(self, subject, relation, obj):
        # Forward: &amp;#39;Mary&amp;#39; -&amp;gt; &amp;#39;parent_of&amp;#39; -&amp;gt; &amp;#39;Tom&amp;#39;
        self.facts[(subject, relation)] = obj
        # Inverse, recorded automatically: &amp;#39;Tom&amp;#39; -&amp;gt; &amp;#39;parent_of&amp;#39; -&amp;gt; &amp;#39;Mary&amp;#39;
        self.reverse_facts[(obj, relation)] = subject

    def query(self, subject, relation):
        return self.facts.get((subject, relation), &amp;quot;I don&amp;#39;t know.&amp;quot;)

    def query_reverse(self, obj, relation):
        return self.reverse_facts.get((obj, relation), &amp;quot;I don&amp;#39;t know.&amp;quot;)


# Demonstration
kb = SymmetricKnowledgeBase()
kb.record_fact(&amp;quot;Mary Lee Pfeiffer&amp;quot;, &amp;quot;parent_of&amp;quot;, &amp;quot;Tom Cruise&amp;quot;)

# Both directions work instantly, no retraining required
print(kb.query(&amp;quot;Mary Lee Pfeiffer&amp;quot;, &amp;quot;parent_of&amp;quot;))      # Tom Cruise
print(kb.query_reverse(&amp;quot;Tom Cruise&amp;quot;, &amp;quot;parent_of&amp;quot;))     # Mary Lee Pfeiffer
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;A Long History of Software That Fails&lt;/h2&gt;
&lt;p&gt;Overestimating AI fits a familiar pattern. Complex systems have always fallen apart over weak requirements, thin testing, and a mismatch between how the machine was designed and what its operators expected.&lt;/p&gt;
&lt;h3&gt;Failures in Traditional Software and Machine Learning&lt;/h3&gt;
&lt;p&gt;Here are some well-known failures side by side, with the technical root cause for each.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;System and intent&lt;/th&gt;
&lt;th&gt;What went wrong&lt;/th&gt;
&lt;th&gt;Technical root cause&lt;/th&gt;
&lt;th&gt;Engineering lesson&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Traditional&lt;/td&gt;
&lt;td&gt;CareFusion Alaris infusion pump: automates medicine dosing&lt;/td&gt;
&lt;td&gt;Class I recall over life-threatening delayed infusions&lt;/td&gt;
&lt;td&gt;Bug in the timing and synchronization protocols&lt;/td&gt;
&lt;td&gt;Safety-critical systems demand rigorous, non-negotiable testing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Traditional&lt;/td&gt;
&lt;td&gt;F-35 target detection: coordinates targets across aircraft&lt;/td&gt;
&lt;td&gt;Planes flying in formation &amp;quot;saw double&amp;quot; targets&lt;/td&gt;
&lt;td&gt;Failed to resolve conflicting sensor coordinates from multiple angles&lt;/td&gt;
&lt;td&gt;Distributed systems need robust sensor fusion and conflict handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Traditional&lt;/td&gt;
&lt;td&gt;Hawaii emergency alert system: warns the public&lt;/td&gt;
&lt;td&gt;False ballistic missile alert, 30 minutes to retract&lt;/td&gt;
&lt;td&gt;Major flaws in the UI and alert origination software&lt;/td&gt;
&lt;td&gt;Interface design is a critical failure point; state must be clear&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML&lt;/td&gt;
&lt;td&gt;Amazon AI recruiting: automates resume screening&lt;/td&gt;
&lt;td&gt;Systematic discrimination against female candidates&lt;/td&gt;
&lt;td&gt;Trained on historical data that reflected and amplified gender imbalance&lt;/td&gt;
&lt;td&gt;Biased datasets get propagated and amplified by the model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML&lt;/td&gt;
&lt;td&gt;Google Health (Thailand): detects retinopathy in eye scans&lt;/td&gt;
&lt;td&gt;Over 20% of clinical scans rejected&lt;/td&gt;
&lt;td&gt;Lab-trained model failed under poor lighting and low bandwidth in clinics&lt;/td&gt;
&lt;td&gt;Evaluate models in the real infrastructure they will run in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML&lt;/td&gt;
&lt;td&gt;Zillow iBuying: automates real estate pricing&lt;/td&gt;
&lt;td&gt;Lost $380 million and shut the unit down&lt;/td&gt;
&lt;td&gt;Failed to adapt to sudden housing volatility during the pandemic&lt;/td&gt;
&lt;td&gt;Models drift; they need continuous monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML&lt;/td&gt;
&lt;td&gt;IBM Watson Oncology: generates treatment plans&lt;/td&gt;
&lt;td&gt;Produced unsafe, hazardous medical advice&lt;/td&gt;
&lt;td&gt;Trained on synthetic, hypothetical cases instead of real patient records&lt;/td&gt;
&lt;td&gt;Synthetic or unrepresentative data creates narrow, unsafe outcomes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;The Swiss Cheese Model and the Moral Crumple Zone&lt;/h3&gt;
&lt;p&gt;Failures in socio-technical systems are rarely one isolated glitch. They happen when several latent weaknesses and active mistakes line up across layers, the way the holes line up in the Swiss Cheese model. The SHELL model frames the same idea: vulnerabilities emerge from the interaction between Software, Hardware, Environment, and Liveware (the humans).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;   Layer 1            Layer 2            Layer 3
  (latent            (interface         (sensor
   defect)            mismatch)          miscalibration)

  ┌──○──┐            ┌──○──┐            ┌──○──┐
  │     │            │     │            │     │
══╪══○══╪════════════╪══○══╪════════════╪══○══╪═══════▶  accident
  │     │            │     │            │     │
  └─────┘            └─────┘            └─────┘

  When the holes align across every layer, the hazard passes through.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When those layers misalign, a moral crumple zone tends to appear. Physical control is heavily automated, but legal and moral responsibility gets deflected onto the nearest human operator, even when their actual control over the system was structurally limited.&lt;/p&gt;
&lt;p&gt;Consider the March 18, 2018 Uber autonomous vehicle crash that killed pedestrian Elaine Herzberg. The perception system kept reclassifying her, cycling between an unknown object, a vehicle, and a bicycle. Every reclassification reset the system&amp;#39;s tracking history, which made the path planner miscalculate her trajectory and delay braking.&lt;/p&gt;
&lt;p&gt;Despite those clear software and organizational failures, the media and the legal system focused almost entirely on the safety driver, Rafaela Vasquez, for not watching the road. That is the moral crumple zone in action: the human operator absorbs the liability when a highly automated, structurally flawed system fails.&lt;/p&gt;
&lt;h2&gt;Handling Probabilistic Uncertainty in Production&lt;/h2&gt;
&lt;p&gt;Building reliable systems on top of machine learning means crossing the line from deterministic computing to probabilistic AI.&lt;/p&gt;
&lt;p&gt;Deterministic systems are predictable. The same input always produces the same output, which is exactly what you want for audit trails, regulatory compliance, and rule-based processing.&lt;/p&gt;
&lt;p&gt;Probabilistic systems deal in likelihoods. They are flexible and handle messy, unstructured input well, but they do not guarantee consistent output. That is not the same as being wrong. A probabilistic system might emit QuickSort on Monday and MergeSort on Tuesday, and both are valid samples from the space of correct solutions.&lt;/p&gt;
&lt;p&gt;The trouble starts when you chain independent probabilistic components together. Reliability degrades multiplicatively. Wire three independent LLM steps in sequence, each with an optimistic 90% success rate, and the math is unforgiving:&lt;/p&gt;
&lt;Math display math=&quot;0.90 \times 0.90 \times 0.90 = 0.729&quot; /&gt;&lt;p&gt;That is a 72.9% total success rate. Factor in the typical 15-20% hallucination rate and unconstrained probabilistic chains become unreliable in production fast.&lt;/p&gt;
&lt;Notice type=&quot;warning&quot;&gt;
  Never chain raw model calls and assume the success rates add up. They multiply
  down. Each probabilistic step you add to a pipeline lowers the ceiling on the
  whole thing.
&lt;/Notice&gt;&lt;p&gt;This also shapes how we design the UI. Instead of letting a model take actions directly, present its output as a suggestion. That keeps the system usable while moving the final validation, and the liability that comes with it, back to the human, which protects the business from the model&amp;#39;s statistical uncertainty.&lt;/p&gt;
&lt;h2&gt;Toward Verifiable Computation: Project Chimera&lt;/h2&gt;
&lt;p&gt;To get past the limits of prompt engineering, we move toward hybrid architectures. That is where neuro-symbolic-causal AI comes in, pairing neural pattern recognition with symbolic logic and counterfactual reasoning.&lt;/p&gt;
&lt;p&gt;Project Chimera is an independent research framework built to enforce safety and stability in autonomous decision-making agents. It stacks three layers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;            UNSTRUCTURED ENVIRONMENT
                      │
                      ▼
   ┌──────────────────────────────────────────┐
   │  NEURAL STRATEGIST (System 1)             │
   │  - Generates strategic hypotheses         │
   │  - Adapts to open-ended inputs            │
   └──────────────────────────────────────────┘
                      │
                      ▼
   ┌──────────────────────────────────────────┐
   │  SYMBOLIC CONSTRAINT ENGINE (Guardian)    │
   │  - Specified and model-checked via TLA+   │
   │  - Repairs non-compliant actions          │
   └──────────────────────────────────────────┘
                      │
                      ▼
   ┌──────────────────────────────────────────┐
   │  CAUSAL INFERENCE ENGINE (System 2)       │
   │  - Models counterfactual relationships    │
   │  - Weighs long-term trade-offs and trust  │
   └──────────────────────────────────────────┘
                      │
                      ▼
            VERIFIED, COMPLIANT DECISION
&lt;/code&gt;&lt;/pre&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Neural Strategist (System 1)&lt;/strong&gt; proposes flexible strategic hypotheses. It is adaptive but unconstrained and structurally fragile on its own.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Symbolic Constraint Engine (Guardian)&lt;/strong&gt; intercepts those proposals and enforces operational, regulatory, and financial invariants. When an action breaks a rule, it does not just reject it, it repairs the action to bring it back inside the safety boundary. The correctness of this layer is proven formally in TLA+.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Causal Inference Engine (System 2)&lt;/strong&gt; models the structural relationships in the operating environment. It lets the agent ask &amp;quot;what would happen if&amp;quot; and weigh short-term gains against long-term metrics like brand trust.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/Steps&gt;&lt;p&gt;Here is a small simulation of how the Guardian intercepts a neural pricing proposal and repairs it to satisfy strict invariants:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;class ChimeraGuardian:
    &amp;quot;&amp;quot;&amp;quot;
    The symbolic guardrail layer of Project Chimera.
    Enforces safety invariants and repairs non-compliant decisions.
    &amp;quot;&amp;quot;&amp;quot;

    def __init__(self, min_margin=0.20, price_floor=10.0):
        self.min_margin = min_margin    # Minimum acceptable profit margin (20%)
        self.price_floor = price_floor  # Hard price floor

    def validate_and_repair(self, proposed_price, unit_cost):
        # 1. Enforce the hard price floor
        if proposed_price &amp;lt; self.price_floor:
            print(f&amp;quot;Proposed price ${proposed_price:.2f} violates the floor!&amp;quot;)
            # Repair: lift the price to the safe floor
            return self.price_floor, &amp;quot;Repaired: price floor violation&amp;quot;

        # Current margin
        current_margin = (proposed_price - unit_cost) / proposed_price

        # 2. Enforce the minimum margin
        if current_margin &amp;lt; self.min_margin:
            print(f&amp;quot;Margin {current_margin:.2%} is below the {self.min_margin:.2%} minimum&amp;quot;)
            # Repair: recompute the price to meet the minimum margin
            repaired_price = unit_cost / (1 - self.min_margin)
            return repaired_price, f&amp;quot;Repaired: insufficient margin (was {current_margin:.2%})&amp;quot;

        # Every invariant passed
        return proposed_price, &amp;quot;Approved&amp;quot;


# Quick test run
guardian = ChimeraGuardian()
cost = 12.0

# An unsafe price below cost (negative margin)
final_price, status = guardian.validate_and_repair(proposed_price=11.0, unit_cost=cost)
print(f&amp;quot;Outcome price: ${final_price:.2f} ({status})&amp;quot;)

# A compliant price
final_price, status = guardian.validate_and_repair(proposed_price=16.0, unit_cost=cost)
print(f&amp;quot;Outcome price: ${final_price:.2f} ({status})&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;What the Numbers Showed&lt;/h3&gt;
&lt;p&gt;Chimera was benchmarked over a 52-week simulation of an e-commerce environment with seasonal demand, price elasticity, and trust dynamics. Pushed toward either Volume (market share) or Margin (profit), the purely neural, LLM-only agents failed badly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chasing volume, unconstrained LLM-only agents priced erratically and racked up a total loss of &lt;strong&gt;$99,000&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Chasing margin, they wrecked customer relationships, eroding brand trust by &lt;strong&gt;48.6%&lt;/strong&gt; to grab short-term gains.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Chimera architecture stayed stable and performed better across the board:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Formal verification:&lt;/strong&gt; the TLA+ model checker explored &lt;strong&gt;174 million states&lt;/strong&gt; and proved &lt;strong&gt;zero invariant violations&lt;/strong&gt; across every possible execution. Every action the Guardian repaired stayed inside the safety boundary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Balanced strategy:&lt;/strong&gt; under &amp;quot;maximize profit and trust,&amp;quot; Chimera earned a cumulative &lt;strong&gt;$1.89 million&lt;/strong&gt;, against $1.69 million for an LLM+Guardian setup and $1.34 million for LLM-only.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Biased strategies:&lt;/strong&gt; Chimera returned &lt;strong&gt;$1.52 million&lt;/strong&gt; under volume optimization and &lt;strong&gt;$1.96 million&lt;/strong&gt; under margin optimization, with some runs topping &lt;strong&gt;$2.2 million&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brand trust:&lt;/strong&gt; it grew trust under both biased strategies, by &lt;strong&gt;1.8%&lt;/strong&gt; and &lt;strong&gt;10.8%&lt;/strong&gt; (and up to &lt;strong&gt;20.86%&lt;/strong&gt; in specific runs).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The cost is latency. Because Chimera runs several validation checks and causal evaluations across multiple hypotheses, it adds a &lt;strong&gt;3x to 5x&lt;/strong&gt; overhead, around &lt;strong&gt;2.8 seconds&lt;/strong&gt; per decision versus &lt;strong&gt;0.7 seconds&lt;/strong&gt; for an unconstrained LLM-only agent. For high-stakes enterprise work, that trade is worth it.&lt;/p&gt;
&lt;h2&gt;A Decision Framework for Using Machine Learning Safely&lt;/h2&gt;
&lt;p&gt;To bring machine learning into a system without getting burned, you need a way to right-size where you spend probabilistic compute. Score every workflow step across four dimensions.&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compliance.&lt;/strong&gt; If a step touches regulatory reporting, financial accounting, or audit-critical decisions, the final call has to run through deterministic, rule-based logic. A probabilistic model can help with early extraction and anomaly flagging, but it does not get the last word.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Outcome consistency.&lt;/strong&gt; If identical inputs must yield identical outputs (payroll, benefits eligibility, SLA ticket routing), use deterministic rules. If variation within bounds is fine (support replies, summarization), a probabilistic model fits.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data sensitivity and structure.&lt;/strong&gt; Highly structured, regulated data like financial ledgers or PII calls for deterministic processing and strict verification. Messy, unstructured data like emails, contracts, and audio recordings justifies the cost and uncertainty of probabilistic pattern matching.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exception complexity.&lt;/strong&gt; Write simple exceptions as deterministic rules. Handle complex but bounded exceptions with probabilistic components nested inside deterministic guardrails. Route the wildly unpredictable ones to a human.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/Steps&gt;&lt;p&gt;As volume grows and you work through the edge cases, encode the proven patterns into deterministic rules rather than handing the model more autonomy. Over time the deterministic engine becomes the backbone of the process, and probabilistic models stay reserved for the specific steps where interpretation actually adds value.&lt;/p&gt;
&lt;h2&gt;Putting It All Together&lt;/h2&gt;
&lt;p&gt;Strip the marketing away and artificial intelligence is not real intelligence. It is a powerful computational simulation of human-like intelligence built on statistical approximation. Once you accept the limits of pattern matching, you can design systems that are safer and more resilient.&lt;/p&gt;
&lt;p&gt;Getting to production means moving away from fragile prompt engineering and toward structured, hybrid design. Three guidelines hold up well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Orchestrate with determinism.&lt;/strong&gt; Keep deterministic workflow engines as the control plane for enterprise operations, so the whole thing stays auditable and predictable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolate and bound the models.&lt;/strong&gt; Treat machine learning models as localized, untrusted microservices. Enforce strict input and output schemas, validate structure, and gate on confidence thresholds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reach for neuro-symbolic-causal integration.&lt;/strong&gt; For complex, multi-objective decisions, pair generative models with formally verified symbolic guardrails (tools like TLA+) and causal inference to protect both safety and brand.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Treat modern AI as a sophisticated statistical instrument rather than an autonomous mind, and you can put these technologies to work without falling into the operational traps that come with automated systems.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;Accordion client:load title=&quot;If AI is not real intelligence, why does it work so well?&quot;&gt;&lt;p&gt;Because a huge amount of useful work is really pattern recognition over data, and that is exactly what these models excel at. Predicting the next token over a massive training corpus captures an enormous amount of structure in language, code, and images. That is genuinely valuable. It is just not the same as understanding, reasoning, or judgment, which is why it breaks in predictable ways at the edges.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;What is the Reversal Curse in simple terms?&quot;&gt;&lt;p&gt;Causal language models learn facts in one direction because they are trained to predict text left to right. If a model learns &amp;quot;A is the parent of B,&amp;quot; it does not automatically know &amp;quot;B is the child of A.&amp;quot; A normal database stores that relationship so you can query it both ways. The model binds the fact to its position in the sequence, so the reverse query can fail.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Why does chaining LLM calls reduce reliability so much?&quot;&gt;&lt;p&gt;Independent probabilistic steps multiply. Three steps at 90% each give you 0.9 x 0.9 x 0.9 = 72.9%, not 90%. Add a 15-20% hallucination rate and a long unconstrained chain quickly becomes too unreliable for production. The fix is to keep deterministic logic in control and bound the probabilistic steps tightly.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;What is a moral crumple zone?&quot;&gt;&lt;p&gt;It is the pattern where a system automates most of the real control but pushes legal and moral responsibility onto the nearest human, even when that person could not realistically have prevented the failure. The 2018 Uber crash is the classic example: the software repeatedly misclassified the pedestrian, yet attention landed mostly on the safety driver.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;When should I use deterministic logic instead of a model?&quot;&gt;&lt;p&gt;Use deterministic rules when you need identical outputs for identical inputs, when the step is compliance or audit critical, or when the data is highly structured and regulated. Reserve probabilistic models for messy, unstructured inputs where some bounded variation is acceptable and interpretation adds value. When in doubt, default to deterministic and wrap the model in guardrails.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Are current models actually &amp;quot;intelligent&amp;quot; or just extremely advanced pattern matchers? r/agi, accessed on May 30, 2026, &lt;a href=&quot;https://www.reddit.com/r/agi/comments/1s4fksn/are_current_models_actually_intelligent_or_just/&quot;&gt;https://www.reddit.com/r/agi/comments/1s4fksn/are_current_models_actually_intelligent_or_just/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Toward human-level concept learning: Pattern benchmarking for AI algorithms, PMC, accessed on May 30, 2026, &lt;a href=&quot;https://pmc.ncbi.nlm.nih.gov/articles/PMC10435961/&quot;&gt;https://pmc.ncbi.nlm.nih.gov/articles/PMC10435961/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pattern Recognition is Something That Intelligent Entities Do, EduGeek Journal, accessed on May 30, 2026, &lt;a href=&quot;https://www.edugeekjournal.com/2025/09/02/pattern-recognition-is-something-that-intelligent-entities-do-but-ai-doesnt-really-do-pattern-recognition/&quot;&gt;https://www.edugeekjournal.com/2025/09/02/pattern-recognition-is-something-that-intelligent-entities-do-but-ai-doesnt-really-do-pattern-recognition/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Stochastic parrot, Wikipedia, accessed on May 30, 2026, &lt;a href=&quot;https://en.wikipedia.org/wiki/Stochastic_parrot&quot;&gt;https://en.wikipedia.org/wiki/Stochastic_parrot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AI vs. Machine Learning: How Do They Differ? Google Cloud, accessed on May 30, 2026, &lt;a href=&quot;https://cloud.google.com/learn/artificial-intelligence-vs-machine-learning&quot;&gt;https://cloud.google.com/learn/artificial-intelligence-vs-machine-learning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cognitive Computing vs. AI: Key Differences, IBM, accessed on May 30, 2026, &lt;a href=&quot;https://www.ibm.com/think/topics/cognitive-computing-vs-ai&quot;&gt;https://www.ibm.com/think/topics/cognitive-computing-vs-ai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &amp;quot;stochastic parrot&amp;quot; critique is based on architectures from a decade ago, Reddit, accessed on May 30, 2026, &lt;a href=&quot;https://www.reddit.com/r/ArtificialSentience/comments/1n5hprj/the_stochastic_parrot_critique_is_based_on/&quot;&gt;https://www.reddit.com/r/ArtificialSentience/comments/1n5hprj/the_stochastic_parrot_critique_is_based_on/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Octopus Test&amp;quot; (Bender and Koller, 2020), economics @ doviak.net, accessed on May 30, 2026, &lt;a href=&quot;https://www.doviak.net/courses/metrics/octopus-test.shtml&quot;&gt;https://www.doviak.net/courses/metrics/octopus-test.shtml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;An Analysis and Mitigation of the Reversal Curse, ACL Anthology, accessed on May 30, 2026, &lt;a href=&quot;https://aclanthology.org/2024.emnlp-main.754.pdf&quot;&gt;https://aclanthology.org/2024.emnlp-main.754.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Reversal Curse: LLMs trained on &amp;quot;A is B&amp;quot; fail to learn &amp;quot;B is A&amp;quot;, arXiv, accessed on May 30, 2026, &lt;a href=&quot;https://arxiv.org/html/2309.12288v4&quot;&gt;https://arxiv.org/html/2309.12288v4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Deterministic vs Probabilistic: Understanding AI System Architecture, Vinci Rufus, accessed on May 30, 2026, &lt;a href=&quot;https://www.vincirufus.com/en/posts/deterministic-vs-probabilistic/&quot;&gt;https://www.vincirufus.com/en/posts/deterministic-vs-probabilistic/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Deterministic vs. Probabilistic AI: Enterprise Workflow Guide, Elementum, accessed on May 30, 2026, &lt;a href=&quot;https://www.elementum.ai/blog/deterministic-vs-probabilistic-ai&quot;&gt;https://www.elementum.ai/blog/deterministic-vs-probabilistic-ai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Beyond Prompt Engineering: Neuro-Symbolic-Causal Architecture for Robust Multi-Objective AI Agents, arXiv, accessed on May 30, 2026, &lt;a href=&quot;https://arxiv.org/abs/2510.23682&quot;&gt;https://arxiv.org/abs/2510.23682&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Real life examples of software development failures, Tricentis, accessed on May 30, 2026, &lt;a href=&quot;https://www.tricentis.com/blog/real-life-examples-of-software-development-failures&quot;&gt;https://www.tricentis.com/blog/real-life-examples-of-software-development-failures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;When AI Goes Astray: High-Profile Machine Learning Mishaps in the Real World, Towards Data Science, accessed on May 30, 2026, &lt;a href=&quot;https://towardsdatascience.com/when-ai-goes-astray-high-profile-machine-learning-mishaps-in-the-real-world-26bd58692195/&quot;&gt;https://towardsdatascience.com/when-ai-goes-astray-high-profile-machine-learning-mishaps-in-the-real-world-26bd58692195/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A Comprehensive Analysis of Safety Failures in Autonomous Driving Using Hybrid Swiss Cheese and SHELL Approach, MDPI, accessed on May 30, 2026, &lt;a href=&quot;https://www.mdpi.com/2673-7590/6/1/21&quot;&gt;https://www.mdpi.com/2673-7590/6/1/21&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Who Is Responsible When Autonomous Systems Fail? Centre for International Governance Innovation, accessed on May 30, 2026, &lt;a href=&quot;https://www.cigionline.org/articles/who-responsible-when-autonomous-systems-fail/&quot;&gt;https://www.cigionline.org/articles/who-responsible-when-autonomous-systems-fail/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Artificial Intelligence</category><category>Software Engineering</category><category>Machine Learning</category><category>Technology Ethics</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0066-ai-is-not-real/hero.jpg" length="0" type="image/jpeg"/></item><item><title>GitHub Actions Reusable Workflows: Build a Shared CI Library Across All Your Repos</title><link>https://mkabumattar.com/blog/post/github-actions-reusable-workflows-shared-ci-library/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/github-actions-reusable-workflows-shared-ci-library/</guid><description>Learn how to simplify and secure your CI/CD at scale using GitHub Actions reusable workflows. This practical guide walks you through the differences between reusable workflows and composite actions, OIDC keyless authentication, and versioning strategies. You will also learn advanced testing methods, like &quot;Patch-on-Test,&quot; to build a secure, fast, and centralized pipeline library your developers will love.</description><pubDate>Wed, 27 May 2026 14:12:56 GMT</pubDate><content:encoded>&lt;h2&gt;Centralizing CI/CD Automation across Repositories&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Why does the duplication of workflow configurations across multiple git repositories create operational risks for engineering organizations?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;#39;ve ever managed more than a handful of code repositories, you know how quickly things can spiral out of control. With modular architectures and microservices, the number of git repositories we manage is skyrocketing. That&amp;#39;s great for development speed, but it&amp;#39;s a massive headache for anyone handling DevOps.&lt;/p&gt;
&lt;p&gt;When you copy and paste the same pipeline configurations across dozens of different repositories, you&amp;#39;re setting yourself up for a nightmare. Let&amp;#39;s say you need to upgrade a Node.js version, patch a security vulnerability, or add a compliance check. You&amp;#39;re stuck opening pull requests in fifty different places. Over time, some repositories get updated while others are forgotten, leading to configuration drift and weird deployment bugs.&lt;/p&gt;
&lt;p&gt;GitHub Actions has a built-in solution for this called reusable workflows. Instead of duplicating code, you can write your standard workflows in one central repository and reference them across your whole organization. When you need to make a change, you update it once in the central repo, and every single project using it gets the update instantly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌────────────────────────────────────────────────────────┐
│               central-shared-workflows                 │
│               (Internal Repository)                    │
│                                                        │
│   ┌────────────────────────────────────────────────┐   │
│   │           node-ci-reusable.yml                 │   │
│   │           (defines workflow_call)              │   │
│   └────────────────────────────────────────────────┘   │
└───────────────────────────┬────────────────────────────┘
                            │
            References via  │  &amp;quot;uses: corporate-org/...&amp;quot;
                            │
      ┌─────────────────────┼─────────────────────┐
      ▼                     ▼                     ▼
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ microservice-a│     │ microservice-b│     │ microservice-c│
│  (Caller Rep) │     │  (Caller Rep) │     │  (Caller Rep) │
│               │     │               │     │               │
│  ci-pipe.yml  │     │  ci-pipe.yml  │     │  ci-pipe.yml  │
└───────────────┘     └───────────────┘     └───────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even better, GitHub integrates these workflows directly into your repository&amp;#39;s dependency graph. That means you can see exactly which repositories are using which version of your shared workflows, making audits and updates a breeze.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# A quick look at how clean your caller workflow becomes
name: Quick Example Pipeline

on:
  push:
    branches: [main]

jobs:
  # Instead of writing 50 lines of test steps, you just call the template
  run-tests:
    uses: corporate-org/shared-workflows/.github/workflows/node-ci-reusable.yml@v1
    secrets: inherit
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Architectural Differences: Reusable Workflows and Composite Actions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What are the functional boundaries and performance trade-offs when selecting between reusable workflows and composite actions?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When you&amp;#39;re building a shared CI/CD library, you&amp;#39;ll constantly run into two features: reusable workflows and composite actions. They both help you keep your pipelines DRY (Don&amp;#39;t Repeat Yourself), but they work at different levels.&lt;/p&gt;
&lt;p&gt;Think of reusable workflows as full pipeline templates that contain one or more jobs. Each job can run on different runners (like Windows or Linux) and run parallelized tasks. On the flip side, composite actions are like little bundles of steps that run inside a single job defined by the caller.&lt;/p&gt;
&lt;p&gt;Choosing the right tool saves you a lot of refactoring later on. Let&amp;#39;s look at how they compare side-by-side:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Architectural Attribute&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Reusable Workflows&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Composite Actions&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;DevOps Implication&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Invocable Level&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Job level (called directly inside a job)&lt;/td&gt;
&lt;td&gt;Step level (called inside a job&amp;#39;s steps)&lt;/td&gt;
&lt;td&gt;Reusable workflows act as top-level pipeline templates, while composite actions are task templates.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-Job Execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported (can define independent jobs and matrices)&lt;/td&gt;
&lt;td&gt;Not supported (everything runs in one job)&lt;/td&gt;
&lt;td&gt;Reusable workflows excel at complex, parallelized build-and-test stages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Secret Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports explicit secrets and automatic inheritance&lt;/td&gt;
&lt;td&gt;Cannot directly accept or hide secrets natively&lt;/td&gt;
&lt;td&gt;Reusable workflows provide a much more secure way to handle deployment keys.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Runner Selection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Declares runner properties (runs-on) internally&lt;/td&gt;
&lt;td&gt;Inherits the runner defined by the calling job&lt;/td&gt;
&lt;td&gt;Reusable workflows can dynamically allocate different machines for different jobs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nesting Capabilities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports up to 10 nested levels of workflows&lt;/td&gt;
&lt;td&gt;Supports up to 10 nested composite actions&lt;/td&gt;
&lt;td&gt;Recent platform updates expanded these limits to handle complex architectures.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execution Logging&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logs each job and step in real-time independently&lt;/td&gt;
&lt;td&gt;Collapses steps under a single execution block&lt;/td&gt;
&lt;td&gt;Reusable workflows make debugging much easier by showing step-by-step logs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Marketplace Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cannot be published to the GitHub Marketplace&lt;/td&gt;
&lt;td&gt;Can be published and versioned in the Marketplace&lt;/td&gt;
&lt;td&gt;Reusable workflows are best kept for internal organization standards.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A smart way to design your pipelines is to use both together. Use reusable workflows as the overall skeleton of your pipeline, and use composite actions for small, repeated steps (like setting up a specific environment or managing a cache) inside those jobs.&lt;/p&gt;
&lt;h2&gt;Defining Reusable Workflows via workflow_call&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;How does a platform engineer declare inputs, outputs, and secrets to build a configurable workflow template?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To make a workflow reusable, you trigger it using the workflow_call event in its on block. This block acts as the public interface for your workflow, letting you declare exactly what inputs, outputs, and secrets it expects from callers.&lt;/p&gt;
&lt;p&gt;You&amp;#39;ll save these YAML files in your repository&amp;#39;s &lt;code&gt;.github/workflows/&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a practical, real-world example of a reusable Node.js pipeline. It checks out the code, sets up Node, handles dependencies, runs tests, and even sends a status output back to the caller:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# .github/workflows/node-ci-reusable.yml
name: Reusable Node.js CI

on:
  workflow_call:
    # Define the parameters that callers can pass in
    inputs:
      node-version:
        description: &amp;#39;The Node.js version to run&amp;#39;
        required: false
        default: &amp;#39;20&amp;#39;
        type: string
      run-coverage:
        description: &amp;#39;Set to true to run unit test coverage&amp;#39;
        required: false
        default: true
        type: boolean
      config-json:
        description: &amp;#39;A JSON string for complex config overrides&amp;#39;
        required: false
        type: string
    # Define the secrets this workflow needs
    secrets:
      NPM_TOKEN:
        description: &amp;#39;Auth token for private npm packages&amp;#39;
        required: true
    # Define outputs to pass data back to the caller
    outputs:
      build-status:
        description: &amp;#39;The final outcome of the build step&amp;#39;
        value: ${{ jobs.build-and-test.outputs.status }}

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    # Map the step output to the job output
    outputs:
      status: ${{ steps.set-status.outputs.status }}
    steps:
      - name: Checkout Application Code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}

      - name: Install Dependencies
        run: |
          if [ -f package-lock.json ]; then
            npm ci
          else
            npm install
          fi
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Run Tests
        run: npm test

      - name: Run Test Coverage
        if: ${{ inputs.run-coverage == true }}
        run: npm run test:coverage

      - name: Parse Complex Configuration
        if: ${{ inputs.config-json != &amp;#39;&amp;#39; }}
        run: |
          # Use jq to parse the JSON input dynamically
          REGION=$(echo &amp;#39;${{ inputs.config-json }}&amp;#39; | jq -r &amp;#39;.region // &amp;quot;us-east-1&amp;quot;&amp;#39;)
          echo &amp;quot;Target region is: $REGION&amp;quot;

      - id: set-status
        name: Export Status
        run: echo &amp;quot;status=success&amp;quot; &amp;gt;&amp;gt; &amp;quot;$GITHUB_OUTPUT&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are a few key practices to call out in this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Input Validation:&lt;/strong&gt; Specifying types (like &lt;code&gt;string&lt;/code&gt; or &lt;code&gt;boolean&lt;/code&gt;) and default values helps prevent runtime crashes when callers forget to pass parameters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handling Complex Data:&lt;/strong&gt; Passing a serialized JSON string (&lt;code&gt;config-json&lt;/code&gt;) lets you bypass flat-parameter limitations. You can easily parse nested properties at runtime using utility tools like &lt;code&gt;jq&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explicit Secrets:&lt;/strong&gt; Declaring required secrets makes the template self-documenting, so developers know exactly what credentials they need to set up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clean Outputs:&lt;/strong&gt; Capturing the build state in &lt;code&gt;$GITHUB_OUTPUT&lt;/code&gt; allows the calling workflow to make smart, conditional decisions later on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Invoking Shared Pipelines from Caller Repositories&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What is the syntax for referencing external workflows and securely passing parameters or inheriting secrets?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once you&amp;#39;ve defined your reusable workflow, calling it from another pipeline is incredibly simple. You use the &lt;code&gt;uses&lt;/code&gt; keyword at the job level of your caller workflow.&lt;/p&gt;
&lt;p&gt;How you reference it depends on where the file is stored:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# If it&amp;#39;s in the same repository
uses: ./.github/workflows/node-ci-reusable.yml

# If it&amp;#39;s in a different repository
uses: {owner}/{repo}/.github/workflows/{filename}@{ref}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To pass values, you use the with block for inputs and the &lt;code&gt;secrets&lt;/code&gt; block for sensitive credentials. Remember that environment variables set at the top workflow level in the caller aren&amp;#39;t passed down to the called workflow. If you need variables inside the called workflow, you have to pass them explicitly as inputs or use repository-level variables through the vars context.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of a caller workflow (&lt;code&gt;.github/workflows/app-delivery.yml&lt;/code&gt;) that runs our Node.js CI template and conditionally deploys the app if everything passes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# .github/workflows/app-delivery.yml
name: Build and Release App

on:
  push:
    branches:
      - main

jobs:
  # Job 1: Call our centralized CI template
  run-ci:
    uses: corporate-org/shared-workflows/.github/workflows/node-ci-reusable.yml@v1.2.0
    with:
      node-version: &amp;#39;22&amp;#39;
      run-coverage: true
      config-json: &amp;#39;{&amp;quot;region&amp;quot;: &amp;quot;us-west-2&amp;quot;, &amp;quot;environment&amp;quot;: &amp;quot;production&amp;quot;}&amp;#39;
    secrets: inherit # Safely passes all repository secrets down

  # Job 2: Run a deployment step only if the CI template finishes successfully
  deploy-application:
    needs: run-ci
    if: ${{ needs.run-ci.outputs.build-status == &amp;#39;success&amp;#39; }}
    runs-on: ubuntu-latest
    steps:
      - name: Deploy Artifacts
        run: echo &amp;quot;Deploying application to production...&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See how clean that caller file is? It orchestrates a multi-step pipeline with barely any code duplication.&lt;/p&gt;
&lt;p&gt;While using &lt;code&gt;secrets: inherit&lt;/code&gt; is incredibly convenient and clean, explicit mapping (like &lt;code&gt;NPM_TOKEN: ${{ secrets.REGISTRY_TOKEN }}&lt;/code&gt;) is often preferred in highly regulated environments to make audits easier and limit credential exposure.&lt;/p&gt;
&lt;h2&gt;Security Governance and Cross-Repository Permissions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;How do organizations enforce least-privilege access and secure private workflows across different repositories?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sharing workflows within a single repo is easy, but sharing them securely across an entire enterprise requires a bit more care. To protect private build configurations and sensitive credentials, GitHub has strict permissions boundaries.&lt;/p&gt;
&lt;p&gt;If your shared workflows live in a private repository, other repositories won&amp;#39;t be able to access them unless you explicitly allow it in the settings.&lt;/p&gt;
&lt;p&gt;Here is how you configure this access:&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to the main page of your private repository hosting the workflows.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Settings&lt;/strong&gt; right under the repo name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the left sidebar, click &lt;strong&gt;Actions&lt;/strong&gt;, then click &lt;strong&gt;General&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scroll down to the &lt;strong&gt;Access&lt;/strong&gt; section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose &lt;strong&gt;Accessible from repositories in the &amp;#39;ORGANIZATION-NAME&amp;#39; organization&lt;/strong&gt;. If you&amp;#39;re on an enterprise plan, you can choose to share across all organizations owned by your enterprise.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/Steps&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌────────────────────────────────────────────────────────┐
│               Settings &amp;gt; Actions &amp;gt; General              │
├────────────────────────────────────────────────────────┤
│  Access Control Policies                               │
│                                                        │
│  ( ) Not accessible from other repositories            │
│                                                        │
│  (•) Accessible from repositories in the               │
│      &amp;#39;corporate-org&amp;#39; organization                      │
│                                                        │
│  ( ) Accessible from all organizations in the          │
│      Enterprise Account                                │
└────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should also keep in mind how outside collaborators interact with these shared workflows. If an outside collaborator has write access to a caller repository, they can run the workflow and view the logs. To prevent unauthorized access, GitHub passes a temporary, scoped token to the runner. This token automatically expires after one hour, protecting your host repository.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re working across separate organizations, the repository hosting the workflows must be public. The calling organization will also need to allow external workflows under &lt;strong&gt;Organization settings -&amp;gt; Actions -&amp;gt; General&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To make your security even tighter, you can use OpenID Connect (OIDC) with your cloud providers (like AWS, GCP, or Azure). Instead of storing long-lived, static cloud keys as GitHub secrets, GitHub issues short-lived JWT tokens on the fly.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s what an OIDC-enabled step looks like inside a reusable workflow:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Example step inside your reusable workflow using OIDC for keyless auth
- name: Configure AWS Credentials via OIDC
  uses: aws-actions/configure-aws-credentials@v4
  with:
    # Use a role ARN instead of storing access keys
    role-to-assume: arn:aws:iam::123456789012:role/github-actions-ci-role
    aws-region: us-east-1
    # Request a JWT token from GitHub&amp;#39;s OIDC provider
    audience: sts.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Versioning Strategies and Release Management&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;How can platform teams publish and maintain workflow updates without introducing breaking changes to dependent pipelines?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Because multiple teams depend on your shared CI/CD library, you have to treat your workflows like production code. If you push an untested change directly to your main branch, you could accidentally break builds across the entire company.&lt;/p&gt;
&lt;p&gt;To keep things stable, you should adopt a clear versioning strategy. Most teams rely on three main pinning methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pinning to a Semantic Version (Best for Stability):&lt;/strong&gt; Referencing a patch version (like &lt;code&gt;@v1.2.0&lt;/code&gt;) ensures that nothing changes under the hood without you knowing, giving you absolute stability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pinning to a Major Version Tag:&lt;/strong&gt; Pinning to a major tag (like &lt;code&gt;@v1&lt;/code&gt;) lets you push safe minor updates and security patches automatically without breaking anything for the end-user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pinning to a Branch:&lt;/strong&gt; Referencing a branch (like &lt;code&gt;@main&lt;/code&gt;) is great for testing features quickly, but it&amp;#39;s dangerous for production because any change can break your pipelines instantly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;#39;re managing a major version tagging strategy, you&amp;#39;ll need to update your tags via the command line when promoting releases:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create and push a specific release tag
git tag -a v1.2.0 -m &amp;quot;Release version 1.2.0&amp;quot;
git push origin v1.2.0

# Force-update your major tag to point to this new commit
git tag -fa v1 -m &amp;quot;Point v1 tag to v1.2.0&amp;quot;
git push origin v1 --force
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In highly secure environments, pinning to a mutable Git tag can still be a risk, since tags can technically be rewritten. The gold standard for security is pinning directly to an immutable Git commit SHA (like &lt;code&gt;@3a82c4...&lt;/code&gt;). Since SHAs can&amp;#39;t be modified, this completely prevents supply chain attacks. You can use tools like Dependabot to automatically open PRs when new versions are released, giving you the best of both security and easy maintenance.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Secure caller using an immutable commit SHA
jobs:
  secure-ci:
    # Pinned to a specific commit SHA for security
    uses: corporate-org/shared-workflows/.github/workflows/node-ci-reusable.yml@3a82c4b8b6c4b2b2b2b2b2b2b2b2b2b2b2b2b2b2
    secrets: inherit
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Organizing a Dedicated Workflows Repository&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What repository layout and templating strategies optimize the distribution of shared CI/CD configurations?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As your shared library grows, you should host your workflows in a dedicated, read-only repository, like &lt;code&gt;your-org/shared-workflows&lt;/code&gt;. This keeps your pipelines separate from application code, makes access control simple, and keeps your project history clean.&lt;/p&gt;
&lt;p&gt;One platform quirk to keep in mind: GitHub Actions forces all reusable workflows to live in the &lt;code&gt;.github/workflows/&lt;/code&gt; directory. This flat layout can make independent versioning difficult for tools like Release Please, which usually depend on folder separation to detect independent packages. Because of this, most teams treat the entire repository as a single package and version all workflows under one release tag.&lt;/p&gt;
&lt;p&gt;Here is a typical layout:&lt;/p&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;your-org/shared-workflows&lt;ul&gt;
&lt;li&gt;.github/&lt;ul&gt;
&lt;li&gt;workflows/&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;node-ci-reusable.yml&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;python-ci-reusable.yml&lt;/li&gt;
&lt;li&gt;docker-publish-reusable.yml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;p&gt;To help developers adopt these standard pipelines quickly, you can set up starter templates in a repository named &lt;code&gt;.github&lt;/code&gt; (e.g., &lt;code&gt;your-org/.github&lt;/code&gt;). When someone creates a new repository in your organization, these templates will show up directly in their Actions initialization menu.&lt;/p&gt;
&lt;p&gt;To set this up, create a folder named &lt;code&gt;workflow-templates&lt;/code&gt; inside your &lt;code&gt;.github&lt;/code&gt; repository. This folder should hold your template YAML file and a JSON metadata file that describes it.&lt;/p&gt;
&lt;p&gt;The folder ends up looking like this:&lt;/p&gt;
&lt;FileTree&gt;&lt;ul&gt;
&lt;li&gt;your-org/.github&lt;ul&gt;
&lt;li&gt;workflow-templates/&lt;ul&gt;
&lt;li&gt;ci-nodejs.yml&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ci-nodejs.properties.json&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/FileTree&gt;&lt;p&gt;Here is a sample properties file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;// workflow-templates/ci-nodejs.properties.json
{
  &amp;quot;name&amp;quot;: &amp;quot;Node.js Enterprise CI&amp;quot;,
  &amp;quot;description&amp;quot;: &amp;quot;Standardized Node.js build pipeline using our approved reusable workflow.&amp;quot;,
  &amp;quot;iconName&amp;quot;: &amp;quot;nodejs&amp;quot;,
  &amp;quot;categories&amp;quot;: [&amp;quot;Continuous Integration&amp;quot;, &amp;quot;Node&amp;quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside your template file, you can use the &lt;code&gt;$default-branch&lt;/code&gt; placeholder so GitHub dynamically swaps it with the repository&amp;#39;s default branch on setup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# workflow-templates/ci-nodejs.yml
name: Node.js CI Pipeline

on:
  push:
    branches: [$default-branch]
  pull_request:
    branches: [$default-branch]

jobs:
  run-ci:
    # Automatically targets your organization&amp;#39;s shared workflow
    uses: your-org/shared-workflows/.github/workflows/node-ci-reusable.yml@v1
    secrets: inherit
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Advanced Testing Patterns, Optimization, and Maintenance&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;How can engineers test workflow changes locally and optimize execution speeds while adhering to platform constraints?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Testing updates to a shared workflow can be tricky. GitHub Actions validates your entire pipeline structure before it ever starts a runner. If you try to run a test workflow that points to an unmerged change on a remote branch, the pre-flight check will fail, crashing the run immediately.&lt;/p&gt;
&lt;p&gt;To bypass this without cluttering your production code with messy test flags, you can use a &amp;quot;Patch-on-Test&amp;quot; strategy. This lets you keep your production files pointing to clean references, while dynamically swapping them for local relative paths on the runner during test runs.&lt;/p&gt;
&lt;p&gt;Here is a test workflow (&lt;code&gt;.github/workflows/test-suite.yml&lt;/code&gt;) that checks out the repository and uses a &lt;code&gt;sed&lt;/code&gt; command to patch the references right before running them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# .github/workflows/test-suite.yml
name: Test Shared Workflows

on:
  push:
    branches:
      - &amp;#39;feature/*&amp;#39;
  pull_request:

jobs:
  test-workflow:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      # Use sed to temporarily swap the remote ref for the local relative file path
      - name: Patch Reusable Reference for Testing
        run: |
          sed -i &amp;#39;s|your-org/shared-workflows/.github/workflows/node-ci-reusable.yml@v1|./.github/workflows/node-ci-reusable.yml|g&amp;#39; .github/workflows/integration-test-caller.yml

      # Run the caller workflow using our local file changes
      - name: Run Integration Tests
        uses: ./.github/workflows/integration-test-caller.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To solve this natively, the GitHub Actions team proposed the relative path syntax prefix &lt;code&gt;$/&lt;/code&gt;. When this is fully supported, writing &lt;code&gt;uses: $/path/to/action&lt;/code&gt; tells the runner to resolve the path relative to the workflow file that called it, keeping references safe and clean across PRs and releases.&lt;/p&gt;
&lt;p&gt;As your CI/CD platform scales, you should also focus on keeping execution times fast and costs low:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Caching Dependencies:&lt;/strong&gt; Use deterministic installation commands (like &lt;code&gt;npm ci&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt;/&lt;code&gt;pnpm&lt;/code&gt; commands with &lt;code&gt;--frozen-lockfile&lt;/code&gt;) to speed up builds. Keep an eye on storage limits, since GitHub caps caching at 10 GB per repository.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parallel Execution:&lt;/strong&gt; Run independent jobs in parallel instead of chaining them sequentially.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrency Controls:&lt;/strong&gt; Use concurrency keys to automatically cancel older, outdated runs when a developer pushes a new commit to the same branch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bypassing Matrix Limits:&lt;/strong&gt; While GitHub limits job matrices to 256 combinations, you can bypass this by nesting reusable workflows. By nesting matrices up to three levels deep, you can theoretically run up to 256^3 (over 16 million) jobs per run, which is perfect for heavy matrix testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using these advanced patterns helps you build a CI/CD library that&amp;#39;s secure, fast, and incredibly easy for your team to maintain.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can environment variables set in a caller workflow be accessed directly within a reusable workflow?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, environment variables defined in the env context of a caller workflow don&amp;#39;t propagate to the called reusable workflow. Similarly, any environment variables you set inside the called workflow won&amp;#39;t be accessible back in the caller workflow. You must pass data explicitly using inputs or return it to the caller via job outputs.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What is the maximum nesting depth allowed for GitHub Actions reusable workflows?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub Actions supports up to 10 nested levels of reusable workflows. Additionally, you can call a maximum of 50 unique reusable workflows across your entire nested execution tree in a single run.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can secrets be shared with reusable workflows without exposing them individually in the YAML configuration?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can use the &lt;code&gt;secrets: inherit&lt;/code&gt; directive inside your caller job. This automatically passes all of your caller repository&amp;#39;s secrets, along with your organization-level secrets, straight to the called reusable workflow.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can reusable workflows be published directly to the public GitHub Marketplace?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, you can&amp;#39;t publish reusable workflows to the GitHub Marketplace. They can only be shared by hosting them in public, internal, or private repositories and referencing them directly by their repository path and Git reference.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does GITHUB_TOKEN permissions inheritance work between caller and called workflows?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;By default, your called workflow inherits the GITHUB_TOKEN permissions of the caller. However, you can restrict or elevate these privileges inside your reusable workflow by declaring a custom permissions block under the workflow_call trigger.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Why do workflows referencing unmerged test branches fail with static analysis errors before executing?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub Actions runs a pre-flight static analysis on your entire pipeline graph before it actually runs anything. If your workflow references a remote branch or tag that doesn&amp;#39;t exist yet, this check fails and stops your pipeline in its tracks. This happens regardless of any conditional if statements, which is why we use the &amp;quot;Patch-on-Test&amp;quot; strategy.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Reusable workflows turn CI/CD from a copy-paste chore into a single source of truth. By defining your standard pipelines once with &lt;code&gt;workflow_call&lt;/code&gt;, calling them with a clean &lt;code&gt;uses&lt;/code&gt; line, and locking everything down with explicit secrets and OIDC, you get pipelines that are easier to audit and far less prone to drift. Pair that with a clear versioning strategy (semantic tags or immutable SHAs), a dedicated workflows repository, and a &amp;quot;Patch-on-Test&amp;quot; approach for safe changes, and you&amp;#39;ve built a shared CI library that scales with your organization instead of fighting it.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;How to Create Reusable Workflows in GitHub Actions - OneUptime, accessed on May 27, 2026, &lt;a href=&quot;https://oneuptime.com/blog/post/2026-01-25-github-actions-reusable-workflows/view&quot;&gt;https://oneuptime.com/blog/post/2026-01-25-github-actions-reusable-workflows/view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Reusing workflow configurations - GitHub Docs, accessed on May 27, 2026, &lt;a href=&quot;https://docs.github.com/en/actions/concepts/workflows-and-actions/reusing-workflow-configurations&quot;&gt;https://docs.github.com/en/actions/concepts/workflows-and-actions/reusing-workflow-configurations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Organization best practices for reusable workflows and actions for an enterprise? - GitHub Community, accessed on May 27, 2026, &lt;a href=&quot;https://github.com/orgs/community/discussions/171037&quot;&gt;https://github.com/orgs/community/discussions/171037&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Best practices for structuring complex GitHub Actions workflows? - GitHub Community, accessed on May 27, 2026, &lt;a href=&quot;https://github.com/orgs/community/discussions/187543&quot;&gt;https://github.com/orgs/community/discussions/187543&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub Actions Workflows: Patterns &amp;amp; Best Practices - DEV Community, accessed on May 27, 2026, &lt;a href=&quot;https://dev.to/thesius_code_7a136ae718b7/github-actions-workflows-github-actions-patterns-best-practices-pge&quot;&gt;https://dev.to/thesius_code_7a136ae718b7/github-actions-workflows-github-actions-patterns-best-practices-pge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;New releases for GitHub Actions - November 2025 - GitHub Changelog, accessed on May 27, 2026, &lt;a href=&quot;https://github.blog/changelog/2025-11-06-new-releases-for-github-actions-november-2025/&quot;&gt;https://github.blog/changelog/2025-11-06-new-releases-for-github-actions-november-2025/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Reusable Workflow Depth Limit - GitHub Community, accessed on May 27, 2026, &lt;a href=&quot;https://github.com/orgs/community/discussions/8488&quot;&gt;https://github.com/orgs/community/discussions/8488&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>CI/CD</category><category>DevOps</category><category>GitHub Actions</category><category>Automation</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0104-github-actions-reusable-workflows-shared-ci-library/hero.png" length="0" type="image/jpeg"/></item><item><title>Kubernetes Networking Demystified: CNI Plugins, Network Policies, and Pod-to-Pod Communication</title><link>https://mkabumattar.com/blog/post/kubernetes-networking-cni-plugins-policies-guide/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/kubernetes-networking-cni-plugins-policies-guide/</guid><description>A friendly, technical guide to Kubernetes networking. We cover how CNI plugins like Calico and Cilium work, how to write Network Policies, and how to debug those annoying connectivity issues.</description><pubDate>Mon, 13 Apr 2026 20:02:59 GMT</pubDate><content:encoded>&lt;p&gt;If you&amp;#39;ve spent any time with Kubernetes, you know that networking is often the part that makes people&amp;#39;s heads spin. It feels like magic until something breaks, and then you&amp;#39;re staring at a maze of virtual interfaces and iptables rules. But once you peel back the layers, it&amp;#39;s actually built on some very logical, albeit different, principles. Let&amp;#39;s break down how it all works so you can feel confident managing your cluster.&lt;/p&gt;
&lt;h2&gt;What is Kubernetes Networking and Why Does it Feel So Complex?&lt;/h2&gt;
&lt;p&gt;At its heart, Kubernetes networking is about making sure every part of your application can talk to every other part, no matter where they&amp;#39;re running. In the old days of running one app on one server, this was easy. But in a cluster, you have hundreds of containers starting and stopping across dozens of machines.&lt;/p&gt;
&lt;p&gt;Kubernetes simplifies this by giving every Pod its own unique IP address. Think of a Pod like a virtual machine or a physical host on a flat network. This &amp;quot;IP-per-Pod&amp;quot; model means you don&amp;#39;t have to worry about port conflicts or managing complex mappings. If two different Pods both want to listen on port 80, they can, because they have different IP addresses.&lt;/p&gt;
&lt;p&gt;There are three big rules that every Kubernetes network must follow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All Pods can talk to all other Pods without using Network Address Translation (NAT).&lt;/li&gt;
&lt;li&gt;Nodes can talk to all Pods on that node (and vice-versa) without NAT.&lt;/li&gt;
&lt;li&gt;A Pod sees its own IP as exactly the same IP that other Pods see for it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These rules create a predictable environment where your apps can just use standard networking. The complexity usually comes from how we implement these rules, especially when we start moving packets across different physical servers.&lt;/p&gt;
&lt;h2&gt;How Does the Container Network Interface (CNI) Connect Your Cluster?&lt;/h2&gt;
&lt;p&gt;Kubernetes doesn&amp;#39;t actually handle the networking itself. Instead, it uses something called the Container Network Interface, or CNI. You can think of CNI as a standardized plug-in system. When the cluster starts a Pod, it calls the CNI plugin and says, &amp;quot;Hey, I need a network for this Pod. Can you set it up?&amp;quot;.&lt;/p&gt;
&lt;p&gt;The CNI plugin does two main jobs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Connectivity:&lt;/strong&gt; It creates the virtual &amp;quot;wires&amp;quot; (interfaces) and connects the Pod to the rest of the network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IP Management (IPAM):&lt;/strong&gt; It picks a unique IP address from a pool and assigns it to the Pod.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can see which CNI you&amp;#39;re using by checking the configuration files on your nodes or looking at the pods running in your &lt;code&gt;kube-system&lt;/code&gt; namespace.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# A quick way to see which CNI pods are running in your cluster
kubectl get pods -n kube-system | grep -E &amp;quot;calico|cilium|flannel&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;How Do You Choose Between Calico, Cilium, and Flannel?&lt;/h2&gt;
&lt;p&gt;Choosing a CNI is a big decision because it affects your cluster&amp;#39;s speed, security, and how much &amp;quot;work&amp;quot; your nodes have to do. Here’s a quick look at the big three:&lt;/p&gt;
&lt;h3&gt;Flannel: The Simple Option&lt;/h3&gt;
&lt;p&gt;Flannel is the &amp;quot;old reliable&amp;quot; of the group. It’s very easy to set up and uses an overlay network (usually VXLAN) to wrap your traffic and send it between nodes. It&amp;#39;s great for small clusters or development environments where you don&amp;#39;t need fancy security rules. The downside? It doesn&amp;#39;t support Network Policies natively, so you can&amp;#39;t easily block traffic between Pods.&lt;/p&gt;
&lt;h3&gt;Calico: The Industry Standard&lt;/h3&gt;
&lt;p&gt;Calico is incredibly versatile. It can run as an overlay, or it can use BGP to route traffic natively without the extra &amp;quot;wrapping&amp;quot; (encapsulation), which makes it very fast. It&amp;#39;s famous for its powerful security engine that handles Network Policies perfectly.&lt;/p&gt;
&lt;h3&gt;Cilium: The Performance Powerhouse&lt;/h3&gt;
&lt;p&gt;Cilium is the new favorite for high-performance clusters. It uses a Linux kernel technology called eBPF to handle packets. By working directly in the kernel, it skips a lot of the traditional networking overhead. It also gives you amazing visibility into what&amp;#39;s happening on your network through a tool called Hubble.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Flannel&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Calico&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cilium&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None (Native)&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Advanced (L7)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;Elite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resource Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very Low&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;How Does Pod-to-Pod Communication Actually Work?&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s look at how a packet gets from Pod A to Pod B. Inside the Pod, there&amp;#39;s a virtual interface called &lt;code&gt;eth0&lt;/code&gt;. This is connected to a &amp;quot;virtual cable&amp;quot; (a veth pair) that leads out to a bridge on the host node.&lt;/p&gt;
&lt;p&gt;If Pod B is on the same node, the bridge just passes the packet over. But if Pod B is on a different node, things get interesting. Depending on your CNI, the packet might be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Encapsulated:&lt;/strong&gt; Wrapped in a new packet (like an envelope) to be sent over the physical network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Routed:&lt;/strong&gt; Sent directly if the physical network knows where the Pod IPs are.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can check your Pod&amp;#39;s internal networking setup with a simple command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Look at the IP and routes inside a running pod
kubectl exec &amp;lt;pod-name&amp;gt; -- ip addr show eth0
kubectl exec &amp;lt;pod-name&amp;gt; -- ip route show
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;How Can You Use Network Policies for Security?&lt;/h2&gt;
&lt;p&gt;By default, every Pod in a cluster can talk to every other Pod. In a production environment, that’s a bit like leaving all your office doors unlocked. &lt;code&gt;NetworkPolicy&lt;/code&gt; resources are how you lock those doors.&lt;/p&gt;
&lt;p&gt;A Network Policy is basically a set of rules that says &amp;quot;only Pod A can talk to Pod B on port 80&amp;quot;. A key thing to remember is that these policies are &amp;quot;allow-lists.&amp;quot; Once you apply a policy to a Pod, everything else is blocked by default.&lt;/p&gt;
&lt;p&gt;I always recommend starting with a &amp;quot;default-deny&amp;quot; policy. This ensures that no traffic moves unless you specifically say it&amp;#39;s okay.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# A &amp;quot;Default Deny&amp;quot; policy that blocks all incoming and outgoing traffic in a namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: my-app
spec:
  podSelector: {} # This empty selector matches ALL pods in the namespace
  policyTypes:
    - Ingress
    - Egress
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you&amp;#39;ve locked everything down, you can add specific &amp;quot;allow&amp;quot; rules for your services.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# This policy allows the &amp;#39;frontend&amp;#39; to talk to the &amp;#39;backend&amp;#39; on port 5432
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: my-app
spec:
  podSelector:
    matchLabels:
      app: backend # The pods we are protecting
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend # The only pods allowed to talk to them
      ports:
        - protocol: TCP
          port: 5432
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What’s the Best Way to Handle Multi-Tenancy?&lt;/h2&gt;
&lt;p&gt;If you&amp;#39;re sharing a cluster between different teams (multi-tenancy), you need to make sure they don&amp;#39;t step on each other&amp;#39;s toes.&lt;/p&gt;
&lt;p&gt;Namespaces are your first line of defense. They give you a way to logically group resources. You should combine these with Resource Quotas so one team doesn&amp;#39;t accidentally use up all the CPU or memory in the cluster.&lt;/p&gt;
&lt;p&gt;For &amp;quot;hard&amp;quot; isolation like if you&amp;#39;re running code for different customers you might want to use node isolation. This ensures that sensitive workloads don&amp;#39;t even share the same physical server as other tenants.&lt;/p&gt;
&lt;h2&gt;How Do You Debug Connectivity Issues When Things Go Wrong?&lt;/h2&gt;
&lt;p&gt;When a connection fails, don&amp;#39;t just guess. Use a systematic approach. Start with the Pod and work your way out.&lt;/p&gt;
&lt;Steps&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Check the Pods:&lt;/strong&gt; Are they running? Do they have IPs?&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get pods -o wide
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Check Endpoints:&lt;/strong&gt; If you&amp;#39;re using a Service, are there actually Pods behind it?&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get endpoints &amp;lt;service-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;Use a Debug Pod:&lt;/strong&gt; I love using &lt;code&gt;netshoot&lt;/code&gt;. It’s a Pod packed with every networking tool you&amp;#39;ll ever need.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Spin up a temporary debug pod to test connections
kubectl run debug-pod --rm -it --image=nicolaka/netshoot -- /bin/bash

# Inside the pod, you can test DNS and connectivity
nslookup my-service
curl -v http://my-service:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;/Steps&gt;&lt;p&gt;One common &amp;quot;gotcha&amp;quot; is the MTU (Maximum Transmission Unit). If your network uses an overlay (like VXLAN), it adds some extra data to every packet. If the total size goes over 1500 bytes, the packet might get dropped. If your small requests work but large file uploads fail, you&amp;#39;re probably hitting an MTU issue.&lt;/p&gt;
&lt;h2&gt;FAQ: Frequently Asked Questions on Kubernetes Networking&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Why can&amp;#39;t my Pod resolve a service name?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is usually a DNS issue. First, check if your CoreDNS pods are actually running: &lt;code&gt;kubectl get pods -n kube-system -l k8s-app=kube-dns&lt;/code&gt;. If they are, check their logs for errors.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What is the difference between Pod-to-Pod and Pod-to-Service communication?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pod-to-Pod is direct. But Pods are ephemeral and their IPs change. Pod-to-Service uses a stable &amp;quot;ClusterIP&amp;quot; that stays the same, even if the underlying Pods are replaced.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Do I really need a Service Mesh?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;A Service Mesh like Istio or Linkerd is great for things like automatic encryption (mTLS) and advanced routing (like canary deployments). But they add complexity. If you just need basic connectivity, a good CNI and some Network Policies are often enough .&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can I run a cluster without a CNI?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nope. Kubernetes provides the model, but it needs a CNI plugin to actually do the work of connecting things.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do I block Pods from reaching the internet?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can use an Egress Network Policy. By specifying which internal CIDR ranges are allowed and leaving out everything else, you effectively block external access.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;Pro-Tips for Production Networking&lt;/h2&gt;
&lt;p&gt;To wrap things up, here are a few best practices for your production clusters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Plan your IP space:&lt;/strong&gt; Make sure your Pod and Service CIDR ranges are big enough for future growth.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Default-Deny:&lt;/strong&gt; It’s much safer to explicitly allow traffic than to try and block everything bad.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitor Latency:&lt;/strong&gt; Tools like Cilium’s Hubble can show you exactly where packets are slowing down, which is a lifesaver when debugging performance issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Networking in Kubernetes is a deep topic, but if you focus on the basics of Pod IPs, CNI plugins, and Network Policies, you&amp;#39;ll be well on your way to mastering it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Cluster Networking | Kubernetes, accessed on March 7, 2026, &lt;a href=&quot;https://kubernetes.io/docs/concepts/cluster-administration/networking/&quot;&gt;https://kubernetes.io/docs/concepts/cluster-administration/networking/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Network Plugins | Kubernetes, accessed on March 7, 2026, &lt;a href=&quot;https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/&quot;&gt;https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Container Network Interface (CNI) Specification - GitHub, accessed on March 7, 2026, &lt;a href=&quot;https://github.com/containernetworking/cni&quot;&gt;https://github.com/containernetworking/cni&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Calico Documentation | Tigera, accessed on March 7, 2026, &lt;a href=&quot;https://docs.tigera.io/calico/latest/about/&quot;&gt;https://docs.tigera.io/calico/latest/about/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cilium Documentation, accessed on March 7, 2026, &lt;a href=&quot;https://docs.cilium.io/&quot;&gt;https://docs.cilium.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes Network Policy | Kubernetes, accessed on March 7, 2026, &lt;a href=&quot;https://kubernetes.io/docs/concepts/services-networking/network-policies/&quot;&gt;https://kubernetes.io/docs/concepts/services-networking/network-policies/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes Network Policy: Use Cases, Examples &amp;amp; Tips [2025] - Tigera.io, accessed on March 7, 2026, &lt;a href=&quot;https://www.tigera.io/learn/guides/kubernetes-security/kubernetes-network-policy/&quot;&gt;https://www.tigera.io/learn/guides/kubernetes-security/kubernetes-network-policy/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ahmetb/kubernetes-network-policy-recipes - GitHub, accessed on March 7, 2026, &lt;a href=&quot;https://github.com/ahmetb/kubernetes-network-policy-recipes&quot;&gt;https://github.com/ahmetb/kubernetes-network-policy-recipes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Multi-tenancy | Kubernetes, accessed on March 7, 2026, &lt;a href=&quot;https://kubernetes.io/docs/concepts/security/multi-tenancy/&quot;&gt;https://kubernetes.io/docs/concepts/security/multi-tenancy/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Debugging Kubernetes Networking | by Usha Nila - Medium, accessed on March 7, 2026, &lt;a href=&quot;https://medium.com/@usha.nila/debugging-kubernetes-networking-c3d55f30dbaF&quot;&gt;https://medium.com/@usha.nila/debugging-kubernetes-networking-c3d55f30dbaF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Diagnose MTU Issues Causing Packet Fragmentation in Kubernetes - OneUptime, accessed on March 7, 2026, &lt;a href=&quot;https://oneuptime.com/blog/post/2026-02-09-diagnose-mtu-packet-fragmentation/view&quot;&gt;https://oneuptime.com/blog/post/2026-02-09-diagnose-mtu-packet-fragmentation/view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes DNS Troubleshooting: Causes &amp;amp; Best Practices - groundcover, accessed on March 7, 2026, &lt;a href=&quot;https://www.groundcover.com/kubernetes-troubleshooting/dns-issues&quot;&gt;https://www.groundcover.com/kubernetes-troubleshooting/dns-issues&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Kubernetes</category><category>Networking</category><category>Cloud Native</category><category>Infrastructure</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0103-kubernetes-networking-cni-plugins-policies-guide/hero.png" length="0" type="image/jpeg"/></item><item><title>Service Mesh Deep Dive: Istio vs. Linkerd</title><link>https://mkabumattar.com/blog/post/service-mesh-istio-vs-linkerd/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/service-mesh-istio-vs-linkerd/</guid><description>Trying to figure out service mesh? This article compares Istio and Linkerd on Kubernetes, looking at how they handle traffic, security, and more. Find out which one might be the best fit for you.</description><pubDate>Mon, 06 Apr 2026 20:02:59 GMT</pubDate><content:encoded>&lt;p&gt;So, you&amp;#39;re diving into the world of cloud-native stuff, huh? Managing all those &lt;strong&gt;microservices&lt;/strong&gt; can get pretty tricky. As you break your apps into smaller, independent pieces, making sure they talk to each other reliably, securely, and in a way you can actually see what&amp;#39;s going on becomes super important. That&amp;#39;s where a &lt;strong&gt;service mesh&lt;/strong&gt; comes in. Think of it as a special layer in your setup that helps your &lt;strong&gt;microservice&lt;/strong&gt; apps communicate better. It basically looks after the network traffic between them, making things run smoother and keeping them safe by watching, redirecting, and controlling access when needed. This layer is often built right into an application to manage how requests get to other services.&lt;/p&gt;
&lt;p&gt;There are tons of good reasons to use a &lt;strong&gt;service mesh&lt;/strong&gt; with &lt;strong&gt;microservices&lt;/strong&gt;. One big one is better &lt;strong&gt;observability&lt;/strong&gt;. You get really detailed, up-to-the-minute info on what&amp;#39;s happening on your network. This includes distributed tracing, which lets you see the whole journey of a request as it hops between services, and real-time metrics and logging, giving you a deep understanding of how your &lt;strong&gt;microservices&lt;/strong&gt; are behaving and if they&amp;#39;re healthy. Better &lt;strong&gt;security&lt;/strong&gt; is another huge plus. A &lt;strong&gt;service mesh&lt;/strong&gt; can beef up your security in lots of ways, giving you a central place to set rules that apply everywhere. Things like mutual TLS (mTLS) encryption, authentication, and authorization make sure your services are talking to each other securely. Plus, a &lt;strong&gt;service mesh&lt;/strong&gt; gives you really fine control over &lt;strong&gt;traffic management&lt;/strong&gt;, with features like smart request routing, load balancing, and support for those cool canary deployments. This means you can really control how requests are handled. Finally, a &lt;strong&gt;service mesh&lt;/strong&gt; makes your system more resilient. It adds features for things like circuit breaking, retries, and timeouts, which helps your apps handle problems gracefully and stops one issue from taking down everything else. This also means you don&amp;#39;t have to put all that communication logic directly into your apps, which makes them easier to manage and scale.&lt;/p&gt;
&lt;p&gt;But, if you&amp;#39;re trying to manage communication in a &lt;strong&gt;microservices&lt;/strong&gt; setup without a &lt;strong&gt;service mesh&lt;/strong&gt;, things can get complicated fast as you add more services. Just keeping an eye on how each service is performing becomes a headache. Trying to coordinate and maintain important stuff like mTLS and access control across lots of services can be a real challenge to do consistently. And in a big &lt;strong&gt;microservices&lt;/strong&gt; world, figuring out where a problem started can be a nightmare. Without a dedicated layer, developers might end up putting communication logic directly into each &lt;strong&gt;microservice&lt;/strong&gt;, which can lead to inconsistencies and more work overall.&lt;/p&gt;
&lt;p&gt;The main thing a &lt;strong&gt;service mesh&lt;/strong&gt; does is take away the complicated parts of network communication from your individual &lt;strong&gt;microservices&lt;/strong&gt;. By putting things like security, observability, and traffic management in one central place, it makes everything more consistent, cuts down on duplicated effort, and makes it easier to run a large number of connected services. As you have more and more &lt;strong&gt;microservices&lt;/strong&gt;, the benefits of having a &lt;strong&gt;service mesh&lt;/strong&gt; really start to shine. While you might be able to handle basic stuff like retries or some security in each service when you only have a few, trying to manage all that across a growing number of services can get crazy complicated. That&amp;#39;s when a &lt;strong&gt;service mesh&lt;/strong&gt; becomes the much better way to handle communication between your services.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Diving Deep into Istio:&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What is Istio and What Problems Does It Solve?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Istio&lt;/strong&gt; is a really popular open-source &lt;strong&gt;service mesh&lt;/strong&gt; that plays well with your existing distributed applications. Its main goal is to give you a consistent and complete way to connect, secure, control, and see what&amp;#39;s happening with your &lt;strong&gt;microservices&lt;/strong&gt;. It came about from a collaboration between Google, IBM, and Lyft and it&amp;#39;s become a key tool for managing deployments, making things more reliable, and boosting &lt;strong&gt;security&lt;/strong&gt; in Kubernetes environments.&lt;/p&gt;
&lt;p&gt;The big problems &lt;strong&gt;Istio&lt;/strong&gt; tries to solve are all about the complexities of managing &lt;strong&gt;traffic management&lt;/strong&gt;, &lt;strong&gt;security&lt;/strong&gt;, and &lt;strong&gt;observability&lt;/strong&gt; when you&amp;#39;ve got a lot of &lt;strong&gt;microservices&lt;/strong&gt;. Without something like &lt;strong&gt;Istio&lt;/strong&gt;, making sure you&amp;#39;re applying the same rules across different ways of communicating and different environments can be really tough. Plus, doing advanced deployment stuff like canary releases, A/B testing, and even intentionally causing problems to test your system often takes a lot of manual work and can be inconsistent across different services. &lt;strong&gt;Istio&lt;/strong&gt; steps in to make all this easier, giving you one place to manage these important parts of running &lt;strong&gt;microservices&lt;/strong&gt;. It lets you enforce things like authentication, encryption, and other crucial rules consistently across all your applications, no matter what technology they&amp;#39;re using. And &lt;strong&gt;Istio&lt;/strong&gt; makes it simpler to do those sophisticated release workflows, giving you the tools to manage traffic flow and make sure your deployments go smoothly and are well-controlled.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Does Istio Work Under the Hood? (Architecture Explained)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The way &lt;strong&gt;Istio&lt;/strong&gt; is put together is based on a clear separation of concerns. It&amp;#39;s divided into two main parts: a data plane and a control plane.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;data plane&lt;/strong&gt; is made up of a bunch of smart proxies, specifically Envoy proxies, that are deployed as sidecars right alongside each &lt;strong&gt;microservice&lt;/strong&gt; instance. These Envoy proxies act like go-betweens, intercepting all the network communication coming in and going out of their associated &lt;strong&gt;microservice&lt;/strong&gt;. Envoy, which is a really fast proxy written in C++, is responsible for handling all the network traffic. It&amp;#39;s the only part of &lt;strong&gt;Istio&lt;/strong&gt; that actually touches the data plane traffic directly. Putting these proxies in as sidecars is a smart move because it lets &lt;strong&gt;Istio&lt;/strong&gt; gather a ton of information about how traffic is behaving. This info is then used to enforce the rules you&amp;#39;ve set up and collect valuable data about what&amp;#39;s happening.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;control plane&lt;/strong&gt; in &lt;strong&gt;Istio&lt;/strong&gt;, which is now mostly handled by a single component called Istiod, has the important job of managing and configuring these Envoy proxies so that traffic gets routed intelligently. Istiod comes as one single package and includes everything needed for service discovery, managing configurations, and handling certificates. It uses the Envoy API (called xDS) to talk to the sidecar proxies, sending them the configurations they need to control how they behave. Before, the control plane had separate parts like Pilot (for traffic management), Citadel (for security), and Galley (for configuration management), but they&amp;#39;ve all been brought together into Istiod to make things simpler.&lt;/p&gt;
&lt;p&gt;Choosing Envoy as the data plane proxy gives &lt;strong&gt;Istio&lt;/strong&gt; a really powerful and well-known proxy that has a big and active community behind it. Envoy&amp;#39;s many features are a big reason why &lt;strong&gt;Istio&lt;/strong&gt; is so capable when it comes to traffic management, security, and observability. However, it&amp;#39;s worth noting that because Envoy does so much, it can also use more resources compared to proxies that are more specialized. This trade-off between having lots of features and being resource-efficient is something to think about when you&amp;#39;re comparing &lt;strong&gt;Istio&lt;/strong&gt; to other &lt;strong&gt;service mesh&lt;/strong&gt; options.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Does Istio Handle Traffic in Your Microservices? (Traffic Management Features)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Istio&lt;/strong&gt; gives you a great set of &lt;strong&gt;traffic management&lt;/strong&gt; features that let you control how traffic and API calls flow between your &lt;strong&gt;microservices&lt;/strong&gt; without having to change any of your application code. This is a really powerful capability, and it&amp;#39;s all managed through a few key configuration tools:&lt;/p&gt;
&lt;p&gt;Virtual Services are super important for defining how incoming requests get routed to specific services within your &lt;strong&gt;service mesh&lt;/strong&gt;. They hide the underlying service instances, which lets you set up sophisticated routing rules based on things like the content of the request, headers, or even where the request came from. This is how you can do things like percentage-based traffic splitting for canary deployments and A/B testing, where you send a small part of your user traffic to a new version of a service while most users still use the old, stable version.&lt;/p&gt;
&lt;p&gt;Destination Rules, on the other hand, are about setting up policies that apply to traffic that&amp;#39;s going to specific services. With these rules, you can define how load balancing should work (like round-robin or sending requests to the service with the fewest current connections), manage connection pooling to make better use of resources, and set up circuit breakers to make your system more resilient by preventing one failing service from taking down others.&lt;/p&gt;
&lt;p&gt;Gateways are essential for managing traffic as it comes into and goes out of your &lt;strong&gt;service mesh&lt;/strong&gt;. They act as entry points, letting you configure things like ports, virtual host routing, TLS settings for secure communication, and even automatically redirecting HTTP connections to HTTPS to make sure everything is secure.&lt;/p&gt;
&lt;p&gt;Finally, Service Entries give you a way to include services that are running outside of your &lt;strong&gt;mesh&lt;/strong&gt;. This is really useful when you need to manage traffic to external APIs or older systems, letting you apply &lt;strong&gt;Istio&lt;/strong&gt;&amp;#39;s &lt;strong&gt;traffic management&lt;/strong&gt; rules to these external dependencies as well.&lt;/p&gt;
&lt;p&gt;The comprehensive set of &lt;strong&gt;traffic management&lt;/strong&gt; tools that &lt;strong&gt;Istio&lt;/strong&gt; offers gives you a lot of control over how traffic moves within your &lt;strong&gt;mesh&lt;/strong&gt; and how it interacts with services outside of it. This means you can do complex deployment strategies, like gradually rolling out new features with canary deployments or running controlled experiments with A/B testing. Plus, being able to route requests based on specific criteria like headers or paths lets you do some pretty sophisticated traffic steering. To make your applications more resilient, &lt;strong&gt;Istio&lt;/strong&gt; makes it easier to set up retries and timeouts to handle temporary issues, as well as circuit breakers to stop overloaded services from affecting the whole system. And &lt;strong&gt;Istio&lt;/strong&gt; even supports traffic mirroring, which lets you duplicate live traffic to a test or monitoring service without affecting the main flow of requests. This gives you valuable insights into how a service handles certain requests. While all these features are great for applications with complicated routing needs, they also mean that &lt;strong&gt;Istio&lt;/strong&gt; can be a bit complex to configure.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Keeping Your Services Secure with Istio&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Istio&lt;/strong&gt; really focuses on &lt;strong&gt;security&lt;/strong&gt;, giving you a strong framework with features like strong identity, powerful policy enforcement, transparent TLS encryption, and complete authentication, authorization, and audit (AAA) tools to keep your &lt;strong&gt;microservices&lt;/strong&gt; and their data safe.&lt;/p&gt;
&lt;p&gt;A key part of &lt;strong&gt;Istio&lt;/strong&gt;&amp;#39;s &lt;strong&gt;security&lt;/strong&gt; approach is that it automatically enforces mutual TLS (mTLS) for all communication between services by default. This makes sure that all communication within your &lt;strong&gt;service mesh&lt;/strong&gt; is both encrypted and mutually authenticated, creating a secure foundation for how your services interact. &lt;strong&gt;Istio&lt;/strong&gt; gives you two main ways to handle authentication: transport authentication, which uses mTLS to verify the identity of the client making a direct connection, and origin authentication, which uses JSON Web Tokens (JWT) to verify the identity of the original end-user or device making the request.&lt;/p&gt;
&lt;p&gt;To make things even more secure, &lt;strong&gt;Istio&lt;/strong&gt; offers comprehensive authorization policies that let you control who can access your services based on the verified identity of the client. You can set up these policies to have really fine-grained access control, making sure only authorized services can talk to each other. The management of the cryptographic keys and certificates, which is crucial for mTLS, is handled by Citadel (now part of Istiod). Citadel automates the process of creating, distributing, and rotating these certificates, which makes it much easier to manage secure communication within your &lt;strong&gt;mesh&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Istio&lt;/strong&gt;&amp;#39;s overall goal with &lt;strong&gt;security&lt;/strong&gt; is to create a zero-trust network environment. This security model works on the idea of &amp;quot;never trust, always verify,&amp;quot; making sure every communication request is authenticated and authorized, no matter where it comes from inside or outside your cluster. By putting these strong &lt;strong&gt;security&lt;/strong&gt; features at the infrastructure level, &lt;strong&gt;Istio&lt;/strong&gt; lets developers focus on their application&amp;#39;s main purpose without having to worry about implementing complex security measures in each individual &lt;strong&gt;microservice&lt;/strong&gt;. This simplifies security management and makes sure you have a consistent security approach across your whole &lt;strong&gt;microservices&lt;/strong&gt; setup.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Understanding Your System: Observability with Istio&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;One of the big strengths of &lt;strong&gt;Istio&lt;/strong&gt; is its complete &lt;strong&gt;observability&lt;/strong&gt; features, which give you detailed insights into how all the service communications within your &lt;strong&gt;mesh&lt;/strong&gt; are behaving. This rich data helps you troubleshoot problems, maintain your applications, and make them run better without needing to add any extra code to your services.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Istio&lt;/strong&gt; generates three main types of data to give you this full picture: metrics, distributed traces, and access logs. Metrics are collected based on the four key things you usually want to monitor: latency, traffic, errors, and saturation. &lt;strong&gt;Istio&lt;/strong&gt; uses the Envoy proxies to gather these important performance indicators and works well with popular monitoring systems like Prometheus and visualization tools like Grafana. Distributed tracing lets you follow individual requests as they go through the different &lt;strong&gt;microservices&lt;/strong&gt; in your system. This gives you an end-to-end view of how requests flow and how your services depend on each other, which helps you understand complex interactions and find performance bottlenecks. &lt;strong&gt;Istio&lt;/strong&gt; supports working with distributed tracing backends like Jaeger, Zipkin, and OpenTelemetry. Finally, &lt;strong&gt;Istio&lt;/strong&gt; can create detailed access logs for all the traffic that goes into and out of the services within your &lt;strong&gt;mesh&lt;/strong&gt;. These logs give you a complete record of each request, including information about where it came from and where it went, letting you audit how your services are behaving at a very detailed level.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;observability&lt;/strong&gt; features in &lt;strong&gt;Istio&lt;/strong&gt; provide a ton of data that&amp;#39;s really important for understanding the health, performance, and overall behavior of your &lt;strong&gt;microservices&lt;/strong&gt; within the &lt;strong&gt;mesh&lt;/strong&gt;. This helps your teams proactively find potential issues, quickly figure out what&amp;#39;s going wrong when there&amp;#39;s a problem, and make informed decisions to improve the performance of your distributed systems. The fact that it works so well with widely used open-source tools for metrics, tracing, and logging makes &lt;strong&gt;Istio&lt;/strong&gt;&amp;#39;s &lt;strong&gt;observability&lt;/strong&gt; features even more valuable, letting teams use their existing monitoring setup and knowledge.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Exploring Linkerd:&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What is Linkerd and Why is it Popular?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Linkerd&lt;/strong&gt; is a lightweight and straightforward &lt;strong&gt;service mesh&lt;/strong&gt; that&amp;#39;s specifically designed for Kubernetes. Created by Buoyant &lt;strong&gt;Linkerd&lt;/strong&gt; has become a CNCF graduated project, which means it&amp;#39;s mature and widely used in the cloud-native world. It&amp;#39;s popular because it&amp;#39;s simple, performs really well, and is easy to use.&lt;/p&gt;
&lt;p&gt;One of the main reasons people like &lt;strong&gt;Linkerd&lt;/strong&gt; is that it doesn&amp;#39;t require as much overhead to run compared to other &lt;strong&gt;service mesh&lt;/strong&gt; options. It has a faster and lighter data plane, which means lower latency and it doesn&amp;#39;t use up as many resources. Plus, &lt;strong&gt;Linkerd&lt;/strong&gt; really focuses on &lt;strong&gt;security&lt;/strong&gt;, with automatic mutual TLS (mTLS) turned on by default, so you get secure communication between your services right out of the box. This &amp;quot;security by default&amp;quot; approach, along with how easy it is to install and set up, makes &lt;strong&gt;Linkerd&lt;/strong&gt; a great choice for organizations that want to get into &lt;strong&gt;service meshes&lt;/strong&gt; without a lot of complexity. Its Kubernetes-native design means it works seamlessly with the most popular platform for managing containers.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Linkerd&amp;#39;s Architecture: Simplicity and Performance&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Linkerd&lt;/strong&gt;&amp;#39;s architecture is all about being simple, with a Control Plane and a Data Plane.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;data plane&lt;/strong&gt; in &lt;strong&gt;Linkerd&lt;/strong&gt; is built on top of really lightweight micro-proxies called Linkerd2-proxy. These proxies, which are written in the memory-safe language Rust, are deployed as sidecar containers right next to each service instance within the same Kubernetes pod. Unlike general-purpose proxies, Linkerd2-proxy is specifically designed and optimized for the &lt;strong&gt;service mesh&lt;/strong&gt; use case, focusing on performance and using very few resources. These proxies transparently handle all the TCP traffic going to and from their associated services.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;control plane&lt;/strong&gt; of &lt;strong&gt;Linkerd&lt;/strong&gt; runs within a dedicated Kubernetes namespace. It&amp;#39;s designed to be modular and simple. Some of the key parts of the control plane include the Destination service, which handles service discovery, policy management, and getting service profiles; the Identity service, which acts like a TLS Certificate Authority, issuing certificates for mTLS; and the Proxy Injector, which automatically adds the Linkerd2-proxy sidecar to your pods.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linkerd&lt;/strong&gt;&amp;#39;s design is based on three main ideas: keep it simple, use minimal resources, and &amp;quot;just works&amp;quot;. This focus on simplicity and performance, especially by using a proxy built specifically for the job in Rust, is what makes &lt;strong&gt;Linkerd&lt;/strong&gt; different from other &lt;strong&gt;service mesh&lt;/strong&gt; options that use more general-purpose proxies like Envoy. This focused approach helps &lt;strong&gt;Linkerd&lt;/strong&gt; achieve its goals of using fewer resources and potentially performing better in certain situations.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Managing Traffic Efficiently with Linkerd&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Linkerd&lt;/strong&gt; offers a set of essential &lt;strong&gt;traffic management&lt;/strong&gt; features that are designed to be efficient and easy to use. While it might not have as many features as some other &lt;strong&gt;service mesh&lt;/strong&gt; solutions, &lt;strong&gt;Linkerd&lt;/strong&gt; provides the core functionalities you&amp;#39;ll need for most common scenarios.&lt;/p&gt;
&lt;p&gt;Some of the key &lt;strong&gt;traffic management&lt;/strong&gt; capabilities in &lt;strong&gt;Linkerd&lt;/strong&gt; include Layer 7 load balancing for HTTP and gRPC traffic, which automatically spreads requests across all the available service endpoints. It also offers Layer 4 load balancing for other TCP-based traffic. To make your applications more reliable, &lt;strong&gt;Linkerd&lt;/strong&gt; provides features for retries and timeouts for HTTP and gRPC requests, which helps the system handle temporary failures gracefully. For doing progressive deployments, &lt;strong&gt;Linkerd&lt;/strong&gt; supports Traffic Split, which lets you do canary releases and blue/green deployments by gradually shifting a portion of your traffic to different versions of a service. Dynamic request routing lets you route individual HTTP requests based on their specific properties. Plus, &lt;strong&gt;Linkerd&lt;/strong&gt; gives you visibility and control over traffic leaving your Kubernetes cluster through the EgressNetwork Custom Resource Definition (CRD). To protect your services from getting overwhelmed, &lt;strong&gt;Linkerd&lt;/strong&gt; offers rate limiting capabilities. Finally, Service Profiles let you configure retries, timeouts, and collect metrics for specific routes, giving you more granular control over &lt;strong&gt;traffic management&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;While &lt;strong&gt;Linkerd&lt;/strong&gt; provides a solid set of basic &lt;strong&gt;traffic management&lt;/strong&gt; features, it&amp;#39;s worth noting that some comparisons suggest &lt;strong&gt;Istio&lt;/strong&gt; might offer a more comprehensive and feature-rich set of capabilities in this area. For organizations with basic to intermediate &lt;strong&gt;traffic management&lt;/strong&gt; needs, &lt;strong&gt;Linkerd&lt;/strong&gt;&amp;#39;s efficient and straightforward features are often enough. However, if you have more complex scenarios that require advanced routing rules or very fine-grained control, &lt;strong&gt;Istio&lt;/strong&gt;&amp;#39;s broader feature set might be more appealing. &lt;strong&gt;Linkerd&lt;/strong&gt; works well with existing ingress controllers, using their capabilities to manage external traffic coming into your cluster.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Securing Communications with Linkerd&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Linkerd&lt;/strong&gt; really focuses on &lt;strong&gt;security&lt;/strong&gt;, with automatic mutual TLS (mTLS) turned on by default for all TCP traffic between pods that are part of the &lt;strong&gt;mesh&lt;/strong&gt;. This feature works right out of the box, making sure all communication within your &lt;strong&gt;service mesh&lt;/strong&gt; is automatically encrypted and mutually authenticated. This gives you a secure way for your services to talk to each other without needing to do any manual setup.&lt;/p&gt;
&lt;p&gt;To make things even more secure, &lt;strong&gt;Linkerd&lt;/strong&gt; offers authorization policies that let you control what kind of traffic is allowed to your meshed pods. With these policies, you can restrict communication to specific services or even particular HTTP routes within a service. The Identity service in &lt;strong&gt;Linkerd&lt;/strong&gt;&amp;#39;s control plane acts as the main TLS Certificate Authority, responsible for creating and managing the certificates used for mTLS. This automated certificate management makes it easier to maintain secure communication within your &lt;strong&gt;mesh&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;One of the things that makes &lt;strong&gt;Linkerd&lt;/strong&gt; stand out in terms of &lt;strong&gt;security&lt;/strong&gt; is that it uses the Rust programming language for its data plane proxy, Linkerd2-proxy. Rust&amp;#39;s memory safety features help prevent many common memory-related security problems that can affect proxies written in languages like C++. This design choice contributes to &lt;strong&gt;Linkerd&lt;/strong&gt;&amp;#39;s reputation as a &lt;strong&gt;service mesh&lt;/strong&gt; that puts security first. The automatic mTLS and the secure foundation provided by Rust make &lt;strong&gt;Linkerd&lt;/strong&gt; a really attractive option for teams that want to easily secure their &lt;strong&gt;microservices&lt;/strong&gt; with minimal setup.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Getting Visibility into Your Services with Linkerd&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Linkerd&lt;/strong&gt; provides a complete set of &lt;strong&gt;observability&lt;/strong&gt; tools that are designed to automatically measure and report on how your applications are behaving within the &lt;strong&gt;service mesh&lt;/strong&gt;. These features require very little, if any, configuration, making it easy for developers and operators to get insights into their distributed systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linkerd&lt;/strong&gt; automatically records top-level metrics, often called &amp;quot;golden metrics,&amp;quot; for HTTP, HTTP/2, and gRPC traffic. These metrics include things like how many requests are happening, the success rate, and how long requests are taking, giving you a good overview of your service health and performance. Plus, &lt;strong&gt;Linkerd&lt;/strong&gt; also captures TCP-level metrics for other types of traffic. You can see these metrics at different levels of detail, including per service, per pair of services communicating, and even per route when you use Service Profiles.&lt;/p&gt;
&lt;p&gt;To help you see and understand this data, &lt;strong&gt;Linkerd&lt;/strong&gt; offers a built-in dashboard and command-line interface (CLI) tools. The dashboard gives you a user-friendly visual representation of your &lt;strong&gt;mesh&lt;/strong&gt;&amp;#39;s health and performance, while the CLI lets you quickly check metrics and the overall status of your services. What&amp;#39;s more, &lt;strong&gt;Linkerd&lt;/strong&gt; works seamlessly with popular open-source monitoring and visualization tools like Prometheus and Grafana through its Viz extension. This means you can use your existing monitoring setup with &lt;strong&gt;Linkerd&lt;/strong&gt;. For a more detailed, real-time look at individual requests, &lt;strong&gt;Linkerd&lt;/strong&gt; provides a feature called the &amp;quot;tap API&amp;quot; that lets you sample requests on demand. This allows operators to watch the live traffic flowing between services, which is really helpful for debugging and troubleshooting. The focus on automatic and easily accessible &lt;strong&gt;observability&lt;/strong&gt; data in &lt;strong&gt;Linkerd&lt;/strong&gt; makes it easier to understand and effectively manage your &lt;strong&gt;microservices&lt;/strong&gt; within the &lt;strong&gt;mesh&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Istio vs. Linkerd: A Detailed Comparison:&lt;/strong&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Istio&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Linkerd&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Architecture&lt;/td&gt;
&lt;td&gt;Feature-rich, Envoy proxy&lt;/td&gt;
&lt;td&gt;Simple, Linkerd2-proxy (Rust)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;Good, getting better&lt;/td&gt;
&lt;td&gt;Excellent, low latency, low resource use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Traffic Management&lt;/td&gt;
&lt;td&gt;Lots of options, very flexible&lt;/td&gt;
&lt;td&gt;Essential features, efficient&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;Comprehensive, very detailed&lt;/td&gt;
&lt;td&gt;Strong, automatic mTLS by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;Rich metrics, tracing, logging&lt;/td&gt;
&lt;td&gt;Key metrics, tracing, logging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ease of Use&lt;/td&gt;
&lt;td&gt;More complex, but improving&lt;/td&gt;
&lt;td&gt;Simple, easy to install and set up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-Cluster&lt;/td&gt;
&lt;td&gt;Robust support&lt;/td&gt;
&lt;td&gt;Good support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VM Support&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No (Kubernetes only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community&lt;/td&gt;
&lt;td&gt;Large, lots of different contributors&lt;/td&gt;
&lt;td&gt;Growing, focused on simplicity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Istio&lt;/strong&gt; and &lt;strong&gt;Linkerd&lt;/strong&gt; take different paths when it comes to building a &lt;strong&gt;service mesh&lt;/strong&gt;. &lt;strong&gt;Istio&lt;/strong&gt; goes for a &amp;quot;everything but the kitchen sink&amp;quot; approach, giving you a wide range of features and lots of ways to customize things, all built on top of the powerful Envoy proxy. This power comes with a bit of a trade-off: it can be more complex and use more resources. It&amp;#39;s designed to work on different platforms, not just Kubernetes, but also virtual machines.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;strong&gt;Linkerd&lt;/strong&gt; keeps things minimal, focusing on simplicity, performance, and being easy to use. Its lightweight design, using the purpose-built Linkerd2-proxy written in Rust, generally leads to lower latency and uses significantly fewer resources, especially in the data plane. While &lt;strong&gt;Istio&lt;/strong&gt;&amp;#39;s performance has gotten better in recent versions, &lt;strong&gt;Linkerd&lt;/strong&gt; often shows better efficiency when resources are tight.&lt;/p&gt;
&lt;p&gt;When it comes to features, &lt;strong&gt;Istio&lt;/strong&gt; offers a broader and more advanced set of capabilities for &lt;strong&gt;traffic management&lt;/strong&gt;, including support for virtual machines and more detailed control over routing and policy enforcement. Both provide strong &lt;strong&gt;security&lt;/strong&gt; with mTLS, but &lt;strong&gt;Istio&lt;/strong&gt; gives you more options for managing policies and integrating with other systems. For &lt;strong&gt;observability&lt;/strong&gt;, both give you lots of data through metrics, tracing, and logging, and they both work with common platforms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linkerd&lt;/strong&gt; really shines when it comes to being easy to use and install. It has a simpler setup process and a lower learning curve, especially if you&amp;#39;re new to &lt;strong&gt;service meshes&lt;/strong&gt;. While &lt;strong&gt;Istio&lt;/strong&gt; has been working on making things easier, it&amp;#39;s still more complex because it has so many features.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Istio&lt;/strong&gt; has a larger and more established community with contributions from big tech companies, which means there&amp;#39;s a wider ecosystem and more readily available support. &lt;strong&gt;Linkerd&lt;/strong&gt; has a growing and active community that&amp;#39;s known for its focus on simplicity and direct interaction.&lt;/p&gt;
&lt;p&gt;Choosing between &lt;strong&gt;Istio&lt;/strong&gt; and &lt;strong&gt;Linkerd&lt;/strong&gt; often comes down to what&amp;#39;s more important to you: having a comprehensive set of features or having something that&amp;#39;s easier to run. If your organization has complex needs and dedicated resources, &lt;strong&gt;Istio&lt;/strong&gt;&amp;#39;s extensive feature set might be the way to go. But if you&amp;#39;re prioritizing performance, ease of use, and a less complicated way to get started with &lt;strong&gt;service meshes&lt;/strong&gt;, especially if you&amp;#39;re mostly working with Kubernetes, then &lt;strong&gt;Linkerd&lt;/strong&gt; is a really good option.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions (FAQ) about Service Mesh, Istio, and Linkerd&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What&amp;#39;s the main job of a service mesh?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;A service mesh acts like a dedicated helper for your microservices, managing and securing how they talk to each other. It makes things more reliable, secure, and easier to see what&amp;#39;s going on.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does a service mesh make my application more secure?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;It sets up security rules, handles who can talk to whom, and encrypts communication, making sure your services are talking to each other safely.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the big differences between Istio and Linkerd?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Generally, Linkerd is lighter, faster, and simpler to use, while Istio has more features and works on more platforms.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does a service mesh affect how well my application runs?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;By making communication between services more efficient, a service mesh can actually make your application run faster and better overall. However, it can also add a little bit of extra work because of the sidecar proxies.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can I only use a service mesh with Kubernetes?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, while some are designed just for Kubernetes (like Linkerd), others like Istio can be used in other environments too.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Do all service meshes use a sidecar?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not necessarily. Using a sidecar proxy is a common way to do it, but there are also newer approaches that don&amp;#39;t use sidecars.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What&amp;#39;s the difference between a service mesh and an API Gateway?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;An API Gateway usually manages traffic coming into your application from the outside (north-south), while a service mesh focuses on traffic between your microservices inside your system (east-west). They often work together.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some real-world examples of using Istio?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Companies use it to make their e-commerce sites more reliable when there&amp;#39;s a lot of traffic, to secure communication between microservices in financial services, and to safely roll out new features in SaaS applications.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some real-world examples of using Linkerd?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;People use it to improve how well their microservices run and to see what&amp;#39;s going on (like loveholidays), to manage traffic efficiently, and to provide security with mTLS for different kinds of organizations.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Is it worth learning about service mesh?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Definitely, especially if you&amp;#39;re dealing with a lot of microservices and need better control over how they interact.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Why are some companies switching from Istio to Linkerd?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Often it&amp;#39;s because Istio can be complex and require a lot of resources to run, so companies are looking for Linkerd&amp;#39;s simplicity and lower resource usage as an easier alternative.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some of the challenges of using a service mesh?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some challenges include the initial complexity of setting it up, the learning curve, the possibility of a slight performance hit, and the work it takes to manage the service mesh itself.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;Making the Right Choice: When to Use Istio vs. Linkerd&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Deciding between &lt;strong&gt;Istio&lt;/strong&gt; and &lt;strong&gt;Linkerd&lt;/strong&gt; really depends on what your organization needs and what your priorities are.&lt;/p&gt;
&lt;p&gt;Think about using &lt;strong&gt;Istio&lt;/strong&gt; if you need a lot of features to handle complicated &lt;strong&gt;traffic management&lt;/strong&gt; and &lt;strong&gt;security&lt;/strong&gt; situations. If you&amp;#39;re using virtual machines along with Kubernetes, &lt;strong&gt;Istio&lt;/strong&gt;&amp;#39;s ability to work on different platforms makes it a good choice. But keep in mind that it can be more complex, so you&amp;#39;ll want to make sure you have a team that knows how to manage it well. &lt;strong&gt;Istio&lt;/strong&gt; is often a favorite for big, enterprise-level setups with advanced needs.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;strong&gt;Linkerd&lt;/strong&gt; is a great option when keeping things simple, having good performance, and being easy to use are most important. If you&amp;#39;re mainly working with Kubernetes and you need a lightweight &lt;strong&gt;service mesh&lt;/strong&gt; that automatically gives you mTLS and essential &lt;strong&gt;observability&lt;/strong&gt; and &lt;strong&gt;traffic management&lt;/strong&gt; features without a lot of extra work, &lt;strong&gt;Linkerd&lt;/strong&gt; is a strong contender. It&amp;#39;s especially good for smaller teams or organizations that are new to &lt;strong&gt;service meshes&lt;/strong&gt; and want something less complicated to start with, particularly if performance and low resource usage are critical.&lt;/p&gt;
&lt;p&gt;The best way to decide is to think about how familiar your team is with cloud-native technologies and carefully consider what your &lt;strong&gt;microservices&lt;/strong&gt; setup really needs. Starting with the simpler &lt;strong&gt;Linkerd&lt;/strong&gt; can be a good move if you&amp;#39;re new to &lt;strong&gt;service meshes&lt;/strong&gt;, while &lt;strong&gt;Istio&lt;/strong&gt; might be something to look at for more advanced needs when you have the resources to manage it.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion: Key Takeaways and Future Trends in Service Mesh&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To wrap things up, both &lt;strong&gt;Istio&lt;/strong&gt; and &lt;strong&gt;Linkerd&lt;/strong&gt; are powerful &lt;strong&gt;service mesh&lt;/strong&gt; tools, and each has its own strengths and weaknesses. &lt;strong&gt;Istio&lt;/strong&gt; offers a feature-rich and highly customizable platform that&amp;#39;s good for complex enterprise environments, while &lt;strong&gt;Linkerd&lt;/strong&gt; provides a simpler, faster, and easier-to-manage solution, especially for Kubernetes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service meshes&lt;/strong&gt; have become really important for dealing with the complexities of modern &lt;strong&gt;microservices&lt;/strong&gt; setups, giving you essential &lt;strong&gt;security&lt;/strong&gt;, &lt;strong&gt;observability&lt;/strong&gt;, and &lt;strong&gt;traffic management&lt;/strong&gt; capabilities. As the cloud-native world keeps changing, there are a few trends shaping the future of &lt;strong&gt;service mesh&lt;/strong&gt; technology. Efforts to create standards like the Service Mesh Interface (SMI) are aiming to make different &lt;strong&gt;mesh&lt;/strong&gt; implementations work better together. The development of architectures that don&amp;#39;t use sidecars promises to reduce the extra work that comes with traditional &lt;strong&gt;service meshes&lt;/strong&gt;. And there&amp;#39;s a constant push to improve the performance and make it easier to adopt and run &lt;strong&gt;service meshes&lt;/strong&gt; so more people can use them.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vmware.com/topics/service-mesh&quot;&gt;What is a Service Mesh? - VMware Glossary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dynatrace.com/news/blog/what-is-a-service-mesh/&quot;&gt;What is service mesh and why do we need it? - Dynatrace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/what-is/service-mesh/&quot;&gt;What is Service Mesh? - AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nttdata.com/global/en/insights/focus/2024/istio-service-mesh-to-provide-traffic-control&quot;&gt;Istio - Service Mesh to provide Traffic Control, Security and Observability for Kubernetes - NTT Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://istio.io/latest/docs/concepts/traffic-management/&quot;&gt;Istio / Traffic Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://istio.io/latest/docs/concepts/security/&quot;&gt;Security - Istio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://istio.io/latest/docs/concepts/observability/&quot;&gt;Istio / Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cncf.io/blog/2023/04/06/introduction-to-the-linkerd-service-mesh/&quot;&gt;Introduction to the Linkerd Service Mesh | CNCF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.solo.io/topics/linkerd/linkerd-architecture&quot;&gt;Linkerd Architecture: Components and Design Principles - Solo.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linkerd.io/&quot;&gt;Linkerd: The only service mesh designed for human beings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://buoyant.io/linkerd-vs-istio&quot;&gt;Linkerd vs Istio, a 2024 service mesh comparison - Buoyant.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://easecloud.io/blog/kubernetes/istio-vs-linkerd-service-mesh-comparison/&quot;&gt;Service Mesh Comparison: Istio vs. Linkerd - EaseCloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://imesh.ai/blog/istio-vs-linkerd-the-best-service-mesh-for-2023/&quot;&gt;Istio vs Linkerd: The Best Service Mesh for 2023 - IMESH&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mkdev.me/posts/the-best-service-mesh-linkerd-vs-kuma-vs-istio-vs-consul-connect-comparison-cilium-and-osm-on-top&quot;&gt;Service Mesh Review: Linkerd, Kuma, Istio &amp;amp; Consul | mkdev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linkerd.io/faq/&quot;&gt;Frequently Asked Questions - Linkerd&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Kubernetes</category><category>Service Mesh</category><category>Cloud Native</category><category>Microservices</category><category>Networking</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0102-service-mesh-istio-vs-linkerd/hero.jpg" length="0" type="image/jpeg"/></item><item><title>GitOps vs. Traditional IaC for Kubernetes: A Comparative Analysis</title><link>https://mkabumattar.com/blog/post/gitops-vs-traditional-iac-kubernetes-deployment/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/gitops-vs-traditional-iac-kubernetes-deployment/</guid><description>Explore GitOps vs. Traditional IaC for Kubernetes. This report compares pull-based GitOps (ArgoCD, Flux) with push-based IaC (Terraform), covering workflows, drift detection, security, and rollbacks. Understand how these approaches manage Kubernetes infrastructure and application configurations for enhanced consistency and reliability.</description><pubDate>Wed, 25 Mar 2026 20:02:59 GMT</pubDate><content:encoded>&lt;p&gt;If you&amp;#39;re managing modern cloud-native applications, especially with Kubernetes, you know it can be a real puzzle. Getting containers to work together, handling all those configurations, and scaling things up across different clusters can get overwhelming fast. For a long time, people did these jobs by hand, using custom scripts, or with scattered configuration files. That often led to mistakes, inconsistencies, and a lot of extra work. But as cloud-native tech keeps moving quickly, we really need better, automated, and consistent ways to manage both our infrastructure and our applications.&lt;/p&gt;
&lt;p&gt;Think about it: Kubernetes environments are getting more complex, and everyone wants faster delivery, more reliability, and fewer human errors. Doing things manually – what some folks call &amp;quot;ClickOps&amp;quot; – just isn&amp;#39;t going to cut it anymore. Those manual steps become a huge roadblock and a big risk, slowing down how quickly a company can adapt and compete in today&amp;#39;s fast-moving cloud world. This pressure means we need smart, automated solutions, and that&amp;#39;s why methods like Infrastructure as Code (IaC) and GitOps have become so popular.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;re going to dive into two big players for managing modern infrastructure: Infrastructure as Code (IaC) and GitOps. Both want to automate and make operations smoother, but they go about it in pretty different ways. Knowing these differences is super important if you&amp;#39;re looking to get the most out of your Kubernetes setups.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What is Infrastructure as Code (IaC) and Why Does it Matter for Kubernetes?&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;How does IaC define your infrastructure?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Infrastructure as Code (IaC) is a core DevOps practice where you manage and set up your computing infrastructure using code or configuration files, instead of doing it by hand with graphical tools or scripts. This approach treats infrastructure configurations just like application code, so you can use version control, keep things consistent, and repeat processes reliably. Just like the same code always produces the same software, IaC makes sure your environments are built the same way every single time.&lt;/p&gt;
&lt;p&gt;A big strength of IaC, and a key idea for GitOps, is that it&amp;#39;s declarative. Instead of giving step-by-step instructions on &lt;em&gt;how&lt;/em&gt; to get to a certain state – which is an imperative way of doing things, common in old-school scripting – IaC simply tells you &lt;em&gt;what&lt;/em&gt; the desired end state of your infrastructure should look like. This makes management much simpler, cuts down on human errors, and lets smart tools handle all the complicated steps needed to reach and keep that desired state. This declarative style is what really makes IaC so good for automation, consistency, and reliability, making it a cornerstone for managing modern infrastructure.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What are the core principles of IaC?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;IaC is built on a few key ideas that make it effective and dependable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idempotency:&lt;/strong&gt; This means that if you run your IaC code multiple times, you&amp;#39;ll always get the same result. Changes only happen if the code detects a difference between what you want (the desired state) and what&amp;#39;s actually there (the current state). This is super important for predictable and reliable deployments, stopping any accidental side effects from running the same operation over and over.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version Control:&lt;/strong&gt; You store your infrastructure code in version control systems, usually Git. This gives you a complete history of every change, which is great for auditing and lets you quickly go back to earlier configurations if you need to.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistency and Standardization:&lt;/strong&gt; IaC helps make sure that environments, like development, testing, and production, are identical and easy to copy across different stages of your development process. This consistency really cuts down on differences and makes troubleshooting much easier across various environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While GitOps explicitly says Git is the &amp;quot;single source of truth,&amp;quot; IaC really sets the stage for this idea. By focusing on version control and treating code as the definitive way to define infrastructure, IaC creates the &lt;em&gt;ability&lt;/em&gt; to have one consistent, auditable source of truth. This shared principle is exactly why GitOps can build so effectively and powerfully on top of IaC.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What are the benefits of IaC in a Kubernetes environment?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Using IaC in a Kubernetes environment brings a lot of good things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Better Tracking and Auditability:&lt;/strong&gt; You can trace every change made to your infrastructure configuration back to specific commits in your version control system. This gives you a clear and complete history of all modifications. That transparency is incredibly valuable for compliance and figuring out problems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reusability:&lt;/strong&gt; Since you&amp;#39;re putting your infrastructure setup into code, you can reuse those configurations across different projects and teams. This really cuts down on duplicated effort and helps standardize things across your organization&amp;#39;s infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistency:&lt;/strong&gt; IaC guarantees uniform environments because it uses the same configuration files. This minimizes configuration errors and differences between various development and deployment stages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; IaC lets you quickly copy environments or adjust resources to meet changing demands, without having to manually configure each piece. This ability is crucial for scaling applications in dynamic cloud environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fewer Errors:&lt;/strong&gt; By automating tasks that used to be manual and prone to mistakes, IaC reduces how much humans are involved and the errors that come with it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster Deployments:&lt;/strong&gt; IaC helps you deliver applications and their supporting infrastructure quickly and at scale. This supports agile development and gets your products to market faster.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;What are the key IaC tools for Kubernetes?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The wide range of IaC tools available, from those that manage cloud provisioning to those that handle Kubernetes-native configurations, shows us that IaC isn&amp;#39;t just one big solution. Instead, it&amp;#39;s a layered way to manage infrastructure. This distinction is important for understanding how different tools work together to manage the entire cloud-native stack effectively.&lt;/p&gt;
&lt;p&gt;Some of the popular IaC tools you&amp;#39;ll find in Kubernetes environments include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Terraform:&lt;/strong&gt; This widely used tool from HashiCorp defines and sets up infrastructure across many cloud providers (like AWS, Azure, GCP) using its declarative HashiCorp Configuration Language (HCL). Terraform is great at provisioning the &lt;em&gt;actual&lt;/em&gt; Kubernetes cluster itself (like EKS, AKS, or GKE) and its related cloud infrastructure pieces, such as Virtual Private Clouds, subnets, storage, and Identity and Access Management (IAM) roles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pulumi:&lt;/strong&gt; An open-source IaC tool that lets you define and manage cloud resources using common programming languages (like Python, TypeScript, Go). This offers flexibility and fits right in with existing codebases, which is appealing to developers who prefer general-purpose languages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ansible:&lt;/strong&gt; A configuration management and automation tool by Red Hat, known for being simple and not needing agents. It uses YAML playbooks to automate infrastructure setup, configuration, and management tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud-specific IaC tools:&lt;/strong&gt; You&amp;#39;ll find examples like AWS CloudFormation, Azure Resource Manager (ARM) templates, and Google Cloud Deployment Manager. These tools are really popular in their specific cloud environments for defining and managing resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Helm:&lt;/strong&gt; A package manager for Kubernetes that uses &amp;quot;charts&amp;quot; to define, install, and upgrade even complex Kubernetes applications. Its templating system gives you a solid way to manage environment-specific values, allowing for consistent deployments with different configurations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kustomize:&lt;/strong&gt; A Kubernetes-native tool that lets you customize raw YAML files. It allows for environment-specific overlays without needing templating, giving you a flexible way to manage configurations for different deployment targets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Crossplane:&lt;/strong&gt; This tool extends Kubernetes to manage external infrastructure resources, letting you provision and manage cloud services directly through Kubernetes APIs. It brings the Kubernetes control plane experience to managing outside cloud services.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Terraform usually works at the &lt;em&gt;infrastructure layer&lt;/em&gt;, setting up the underlying cloud resources and the Kubernetes cluster itself. On the other hand, tools like Helm and Kustomize manage the &lt;em&gt;application and configuration layer&lt;/em&gt; &lt;em&gt;inside&lt;/em&gt; Kubernetes. This clear division of responsibilities among IaC tools, based on how &amp;quot;deep&amp;quot; they go into the infrastructure, means that managing cloud-native infrastructure effectively often requires using several tools. You&amp;#39;ll combine different IaC tools to manage distinct layers of your infrastructure, from the cloud resources underneath to the containerized applications running on Kubernetes.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Unpacking GitOps: A Git-Centric Approach to Kubernetes Management&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What makes GitOps different from traditional IaC?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitOps is a modern way of operating that applies DevOps ideas, especially continuous delivery, to infrastructure automation. It basically uses Git repositories as the &lt;em&gt;single source of truth&lt;/em&gt; for defining and managing &lt;em&gt;all&lt;/em&gt; your infrastructure and application configurations. This approach completely changes how infrastructure is managed by giving you a clear, consistent, and automated way to deploy, monitor, and manage applications, making sure your system&amp;#39;s desired state is always versioned and unchangeable.&lt;/p&gt;
&lt;p&gt;GitOps takes the idea of Infrastructure as Code a step further by adding a strict Git-focused workflow and a continuous reconciliation process, especially tuned for Kubernetes. This means GitOps &lt;em&gt;uses&lt;/em&gt; IaC to define what the desired state should be, but then it enforces a specific workflow (Git-focused, pull-based, continuous reconciliation) to manage and keep that state in a live system.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What are the definition and core principles of GitOps?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The OpenGitOps standards group defines GitOps through four main principles&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Declarative:&lt;/strong&gt; The desired state of the system (how it &lt;em&gt;should&lt;/em&gt; be set up) is clearly stated in Git. This means the configuration tells you the outcome you want, and the system automatically works to match and maintain this defined state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Versioned and Immutable:&lt;/strong&gt; The desired state is stored in Git in a way that makes it unchangeable and versioned, keeping a full history of all modifications. This gives you an accurate audit log for every change, allowing for complete traceability and reproducibility.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pulled Automatically:&lt;/strong&gt; Software agents, often Kubernetes Controllers, automatically &lt;em&gt;pull&lt;/em&gt; the desired state declarations from the Git repository. This &amp;quot;pull-based&amp;quot; model is a key difference from traditional &amp;quot;push-based&amp;quot; CI/CD pipelines, where external tools push changes to the cluster.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuously Reconciled:&lt;/strong&gt; These software agents constantly watch the actual system state within the Kubernetes cluster, compare it to the desired state defined in Git, and automatically apply changes to fix any differences they find. This continuous loop makes sure the system stays in the desired state, actively finding and fixing &amp;quot;configuration drift&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pull-based deployment model that&amp;#39;s central to GitOps offers a big security advantage over traditional push-based CI/CD workflows. In a traditional setup, CI/CD pipelines often need direct write access to production clusters, which can be a weak point for attacks. With GitOps, the agent living &lt;em&gt;inside&lt;/em&gt; the Kubernetes cluster pulls changes from Git. This design means fewer outside CI/CD systems need to hold powerful credentials to the production environment, which cuts down on potential attack areas and centralizes access control and auditing around the Git repository itself. This shift in architecture from push to pull really improves overall security by reducing direct external access to the live environment, making Git the main gatekeeper for changes.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How GitOps extends IaC for Kubernetes&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitOps applies and builds on IaC principles by using Git as the central backbone for all infrastructure management, making sure everything is consistent and reliable. It gives you a structured and automated way to define what your system should look like, specifically Kubernetes manifests and configurations, in Git. Then, it constantly checks and adjusts the actual state of the cluster to match this defined state.&lt;/p&gt;
&lt;p&gt;While Infrastructure as Code (IaC) mainly focuses on &lt;em&gt;defining&lt;/em&gt; infrastructure as code, GitOps takes this idea and turns it into a full &lt;em&gt;operational model&lt;/em&gt;. It&amp;#39;s not just about writing code for infrastructure; it&amp;#39;s about &lt;em&gt;how&lt;/em&gt; that code is managed, deployed, and continuously kept up-to-date in a live system. GitOps effectively turns Git into a dynamic control center for operations, providing the constant feedback loop and automated reconciliation needed for very active Kubernetes environments. IaC gives you the &lt;em&gt;declarative definition&lt;/em&gt; (the &amp;quot;what&amp;quot;), while GitOps gives you the &lt;em&gt;automated process&lt;/em&gt; for deploying, monitoring, and maintaining that definition in a live system (the &amp;quot;how&amp;quot;). This moves beyond static configuration files to a dynamic operational workflow. GitOps puts IaC into action, providing the continuous feedback loop and automation needed to manage the lifecycle of applications and infrastructure in dynamic Kubernetes environments, making Git the central point of control for operations.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What are the key GitOps tools?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While both ArgoCD and Flux do a great job of implementing GitOps, their core design philosophies are quite different. This fundamental distinction affects how organizations choose, customize, and fit these tools into their broader cloud-native ecosystem, influencing how users experience them and how flexible the architecture can be.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ArgoCD:&lt;/strong&gt; This tool is described as a &amp;quot;declarative, GitOps continuous delivery tool for Kubernetes.&amp;quot; ArgoCD constantly watches Git repositories for changes and automatically deploys those changes to the cluster. It compares the state you&amp;#39;ve declared in Git with what&amp;#39;s actually running in the cluster and applies any necessary changes to fix discrepancies.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Key Features:&lt;/strong&gt; Automated synchronization, managing multiple clusters from one interface, better security features like Role-Based Access Control (RBAC) and Single Sign-On (SSO) integration, full audit trails, a Kubernetes-native architecture, powerful visualization and monitoring through a web UI, and built-in rollback capabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strengths:&lt;/strong&gt; ArgoCD offers a comprehensive and easy-to-use web UI, application-focused management, advanced features like ApplicationSets for managing many applications at once, and its own custom RBAC system. Organizations often prefer it if they&amp;#39;re looking for a more &amp;quot;platform-like&amp;quot; and opinionated experience, giving them a complete view of application states and deployments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Cases:&lt;/strong&gt; Making Kubernetes deployments smoother, improving teamwork between development and operations teams, and providing a solid base for continuous delivery in cloud-native environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flux CD:&lt;/strong&gt; An open-source continuous delivery tool designed to implement GitOps processes for Kubernetes clusters. It runs as a set of controllers right inside your Kubernetes cluster, constantly watching connected Git repositories for changes and synchronizing the cluster&amp;#39;s state to match the configuration defined in Git.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Key Features:&lt;/strong&gt; Automated software rollouts, strong rollback capabilities, support for multiple environments, native Kubernetes RBAC support, a multi-tenant enabled architecture, and compatibility with the Kubernetes Cluster API for managing other clusters. It easily integrates with a wide range of ecosystem tools including Helm, Kustomize, Grafana, Prometheus, Kyverno, and SOPS. Flux also includes image reflector and automation controllers for automatically updating container images, and notification controllers for alerts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strengths:&lt;/strong&gt; Flux focuses on simplicity and smooth integration with Kubernetes APIs, following an extensible &amp;quot;toolkit&amp;quot; approach. It relies on Kubernetes-native RBAC and has strong community support. It&amp;#39;s a good fit for building custom tools on top and is becoming a popular choice for external vendors integrating GitOps.&lt;/li&gt;
&lt;li&gt;Ultimately, choosing between ArgoCD and Flux depends on whether an organization prefers a ready-made, opinionated solution or a highly customizable, Kubernetes-native approach, and how comfortable they are with dedicated GitOps applications versus a collection of integrated Kubernetes controllers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;GitOps vs. Traditional IaC: A Head-to-Head Comparison for Kubernetes Deployments&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;How do their deployment workflows differ (Push vs. Pull)?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The main difference between GitOps and traditional IaC comes down to how they deploy things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Traditional IaC (Push-based):&lt;/strong&gt; In this workflow, developers commit new code changes to version control. A Continuous Integration (CI) server then runs automated tests. If everything looks good, it &lt;em&gt;pushes&lt;/em&gt; the newly built container image to a repository. After that, an automated deployment tool &lt;em&gt;pushes&lt;/em&gt; these containers to the production environment. The CI part is usually at the heart of this whole process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitOps (Pull-based):&lt;/strong&gt; The initial CI process (code commit, testing, image building) pretty much stays the same. However, the deployment phase is quite different. When a new container image or configuration change is ready, a GitOps agent, often a Kubernetes Controller like ArgoCD or Flux, &lt;em&gt;pulls&lt;/em&gt; the desired state from the Git repository and applies it to the cluster. In this model, Git itself is central, acting as the single source of truth that the agent constantly monitors and synchronizes with.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pull-based model of GitOps naturally offers a big security benefit over traditional push-based IaC. In traditional setups, CI/CD pipelines often need direct, powerful write access to target production clusters, which can be a significant security risk or attack point. With GitOps, the agent running &lt;em&gt;inside&lt;/em&gt; the cluster pulls changes from Git. This design means fewer external systems, like CI servers, need direct, high-privilege credentials to the live production environment. This reduces the overall attack surface and centralizes access control and auditing mainly around the Git repository. This fundamental architectural difference leads to a stronger security posture for GitOps by design, effectively making Git the primary gatekeeper and audit log for all changes, rather than relying on potentially more vulnerable external pipelines.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How do they manage infrastructure state and detect configuration drift?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Managing infrastructure state and finding configuration drift are critical areas where GitOps and traditional IaC approaches go in different directions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Traditional IaC:&lt;/strong&gt; Defines the desired state of infrastructure through code. Tools like Terraform keep a &amp;quot;state file&amp;quot; that tracks the current actual state of the infrastructure, which they then compare against the desired state for consistency. However, configuration drift – when the actual state deviates from the desired state – can still happen because of manual changes made directly to the infrastructure or inconsistencies missed during deployment. Finding drift in traditional IaC often means running a command, like terraform plan, to compare the live state against the IaC files. This can be a manual or scheduled process.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Challenges:&lt;/strong&gt; If someone makes manual changes directly to the environment, those changes can accidentally get reverted during the next automated IaC deployment. This could lead to instability, unexpected behavior, or even reintroducing security vulnerabilities. Detecting and managing drift at a large scale can be tough without constant, automated monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitOps:&lt;/strong&gt; Git is clearly set as the single source of truth for the desired state of the entire system. GitOps agents (Kubernetes Controllers) constantly monitor the actual state of the Kubernetes cluster and compare it with the desired state defined in the Git repository. If they find any difference (drift), the agent automatically fixes it by applying the desired state from Git, essentially &amp;quot;self-healing&amp;quot; the cluster.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; This approach offers active detection and automated fixing of configuration drift, making sure the system is continuously consistent and reliable. This constant enforcement also subtly encourages teams to commit any manual changes back to version control, because they know those changes will otherwise be reverted.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Traditional IaC often relies on &lt;em&gt;reactive&lt;/em&gt; drift detection. This means you perform a manual or scheduled check, like running a terraform plan, to find differences between the desired and actual states. GitOps, however, is all about &lt;em&gt;proactive, continuous reconciliation&lt;/em&gt;. This means the system doesn&amp;#39;t just &lt;em&gt;tell&lt;/em&gt; you about drift; it actively and automatically &lt;em&gt;fixes&lt;/em&gt; it by constantly enforcing the desired state from Git. This continuous feedback loop is a big operational advantage, turning drift management from a reactive troubleshooting burden into a built-in, self-correcting mechanism. This leads to higher stability and reliability with less human involvement. This continuous, automated reconciliation in GitOps fundamentally changes how we handle drift management, moving it from a reactive, human-driven task to a proactive, system-driven, self-healing process. This significantly improves the reliability and consistency of Kubernetes environments.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What are the security implications and best practices for each?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Security is super important in any infrastructure management strategy, and both IaC and GitOps have their own distinct things to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Traditional IaC Security:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vulnerabilities:&lt;/strong&gt; Common security flaws include mistakes in IaC files (like insecure default settings or open ports), vulnerabilities in container images, and the risky practice of putting sensitive secrets (passwords, API keys) directly into code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt; Use IaC scanners to find misconfigurations early in development. Use container scanning tools to detect known vulnerabilities in container images. Employ secrets scanning tools to stop sensitive data from being hard-coded. Put these security checks right into your CI/CD pipelines to automatically enforce security policies. Plus, use policy-as-code tools like Open Policy Agent (OPA) or Kyverno to make sure configurations follow your organization&amp;#39;s security policies before deployment. Most importantly, prevent direct access to the Kubernetes API server from unauthorized sources, make sure all cluster communications use TLS, and encrypt sensitive data stored in etcd.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitOps Security:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; GitOps naturally provides stronger security. Git&amp;#39;s cryptographic features for tracking changes and proving who made them improve the integrity of your desired state. The unchangeable and auditable nature of Git history is invaluable for responding to incidents and rebuilding systems after a breach. The pull-based model reduces potential attack areas by limiting the need for CI/CD tools to have direct, powerful access to the cluster. It also actively finds and fixes unauthorized changes made directly to the cluster.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Challenges:&lt;/strong&gt; A big challenge is securely managing secrets. Storing sensitive information directly in plain text in Git repositories is a major security risk. Also, making sure you have fine-grained access control to sensitive Git repositories themselves is crucial, because unauthorized write access could introduce harmful changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt; To handle secrets, encrypt them before storing them in Git using tools like Bitnami Sealed Secrets or Mozilla SOPS. Another option is to store references to secrets in external, specialized secret backends (like HashiCorp Vault, AWS Secrets Manager) and use tools like External Secrets Operator to pull and inject them into the cluster during deployment. Enforce strong Role-Based Access Control (RBAC) at the Git repository level to control who can suggest and merge changes. Other general security practices include network segmentation, following the principle of least privilege, keeping all software components up to date, and continuously monitoring and auditing your system.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both IaC and GitOps fundamentally promote &amp;quot;shift-left&amp;quot; security, meaning you can do security checks earlier in the development process by defining infrastructure and configurations in code. However, GitOps really steps this up by making Git the central control point for &lt;em&gt;all&lt;/em&gt; operational changes. This centralized, Git-driven workflow makes security auditing, compliance enforcement, and fixing vulnerabilities more consistent, transparent, and naturally integrated throughout the entire operational lifecycle. This strengthens your overall security posture by design. While IaC allows for early security checks on the code itself, GitOps &lt;em&gt;enforces&lt;/em&gt; a process where &lt;em&gt;every&lt;/em&gt; change, including security updates or fixes, must start and be reviewed in Git. This creates a more comprehensive and auditable security posture across the entire change management process.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How do they handle rollbacks and ensure system reliability?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Being able to quickly and reliably undo changes is super important for system reliability:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Traditional IaC:&lt;/strong&gt; Rollbacks are generally possible by going back to an earlier version of your IaC codebase. This involves finding the last known stable configuration files and reapplying them to your infrastructure. This process can sometimes be manual or partly automated, depending on your tools and pipeline setup.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitOps:&lt;/strong&gt; Offers a built-in and much simpler way to roll back. Because the desired state of your entire system is stored and versioned in Git, going back to a previous version is as easy as reverting a commit in your Git repository. The GitOps agent then automatically spots this change in Git and brings the cluster back to that previous desired state. This gives you a clear record of changes and really simplifies disaster recovery, since you can recreate your entire system from Git.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Challenges with Stateful Applications:&lt;/strong&gt; While GitOps rollbacks work really well for stateless resources (like container deployments or network configurations), they get tricky with stateful applications, especially databases. Reverting a database schema change (like dropping a column) can lead to permanent data loss, because the reverse operation doesn&amp;#39;t bring back the original data. This shows a critical limitation where GitOps principles alone aren&amp;#39;t enough. You need to handle these situations carefully, often using specialized database operators or migration tools that understand schema intent and data integrity.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GitOps gives you a more predictable and naturally reliable way to roll back because the entire system&amp;#39;s desired state is stored and managed in Git. This is a sharp contrast to traditional methods, where rollbacks might involve more manual steps or a less clear understanding of the exact state you&amp;#39;re reverting to. However, this predictable nature hits a big limit when you&amp;#39;re dealing with stateful data, like databases. While GitOps can revert the &lt;em&gt;code&lt;/em&gt; that defines a database schema, it can&amp;#39;t magically bring back &lt;em&gt;lost data&lt;/em&gt;. This means organizations have to look at specialized solutions, including database operators or careful migration strategies, to truly achieve &amp;quot;rollbackability&amp;quot; for stateful components. This highlights a nuanced challenge in the otherwise seamless promise of GitOps. While GitOps significantly simplifies rollbacks for most Kubernetes resources, it requires a deeper, more specialized approach to managing stateful data, often needing extra tools or patterns beyond the core GitOps framework.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How do they impact team collaboration and auditability?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Both IaC and GitOps really change how teams work together and how easy it is to audit things, though they focus on different aspects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Traditional IaC:&lt;/strong&gt; By putting infrastructure into code, IaC naturally encourages teamwork, because changes are visible in version control and can be reviewed openly. Using version control systems also greatly improves auditability by providing a history of who changed what and when.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitOps:&lt;/strong&gt; Significantly improves collaboration by centralizing all code reviews and important discussions directly within Git pull requests. The Git repository becomes the single, complete place for all infrastructure and application changes. This really helps with bringing new team members on board and makes things more transparent across development and operations teams. This approach gives you a clear, unchangeable record of who made which changes, when, and why, which is crucial for compliance and troubleshooting.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GitOps uses Git not just as a version control system for code, but as the main, centralized hub for &lt;em&gt;all&lt;/em&gt; operational changes. This systematic use of Git&amp;#39;s collaborative features, like pull requests, code reviews, and commit history, naturally leads to better communication and alignment between development and operations teams (&amp;quot;DevOps&amp;quot;) by standardizing the change process around familiar Git workflows. It creates a shared language and process for everyone involved in managing the system. By funneling all changes and discussions through Git&amp;#39;s established collaborative mechanisms, GitOps naturally bridges the traditional communication gaps between development and operations teams. Everyone works from the same &amp;quot;source of truth&amp;quot; using familiar tools. GitOps transforms Git into the central &amp;quot;meeting point&amp;quot; for all infrastructure and application changes, leading to enhanced transparency, accountability, and seamless cross-functional collaboration, which are core tenets of the DevOps philosophy.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a quick look at the key differences:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 1: GitOps vs. Traditional IaC: Key Differences&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Traditional IaC&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;GitOps&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Source of Truth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CI/CD pipeline logic / IaC files&lt;/td&gt;
&lt;td&gt;Git repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deployment Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Push-based (CI pushes to cluster)&lt;/td&gt;
&lt;td&gt;Pull-based (agent pulls from Git)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;External state files / manual tracking&lt;/td&gt;
&lt;td&gt;Git as desired state / continuous reconciliation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Drift Detection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reactive (manual/scheduled checks via plan)&lt;/td&gt;
&lt;td&gt;Proactive (automated agent reconciliation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rollback Mechanism&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Revert IaC files (manual/semi-automated)&lt;/td&gt;
&lt;td&gt;Revert Git commit (automated by agent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Infrastructure definition and provisioning&lt;/td&gt;
&lt;td&gt;Application/Infrastructure operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tooling Examples&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Terraform, Pulumi, Ansible&lt;/td&gt;
&lt;td&gt;ArgoCD, Flux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Implication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Direct cluster access for CI/CD&lt;/td&gt;
&lt;td&gt;Reduced direct cluster access for CI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operational Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Imperative (scripts define steps) or Declarative (tools apply desired state)&lt;/td&gt;
&lt;td&gt;Declarative (system reconciles to Git)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Integrating Terraform with GitOps: The Best of Both Worlds?&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;Can Terraform be &amp;quot;GitOpsed&amp;quot; for Kubernetes infrastructure?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Yes, Terraform&amp;#39;s declarative nature fits really well with GitOps principles. This means you can put Terraform code under version control in Git, and changes can be automatically applied to your infrastructure based on Git merges. Terraform is excellent at setting up the &lt;em&gt;underlying cloud infrastructure&lt;/em&gt; that Kubernetes clusters run on, including virtual machines, networking pieces, databases, and even the Kubernetes cluster itself as a managed service (like EKS, AKS, or GKE). GitOps tools like ArgoCD and Flux then typically manage the &lt;em&gt;applications and configurations deployed within&lt;/em&gt; that Kubernetes cluster.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Exploring patterns for combining Terraform&amp;#39;s provisioning power with GitOps&amp;#39; operational model:&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The different ways you can integrate these tools clearly show that Terraform and GitOps aren&amp;#39;t competing; they actually have strengths that complement each other. Terraform is great at setting up the &lt;em&gt;foundational, broader infrastructure&lt;/em&gt;, like the Kubernetes cluster itself and its cloud resources. GitOps, on the other hand, excels at managing the &lt;em&gt;dynamic state of applications and configurations&lt;/em&gt; deployed &lt;em&gt;on&lt;/em&gt; that foundation. The main challenge is cleanly connecting these two layers while strictly keeping Git as the single source of truth across the entire stack. The most effective strategy often involves using both tools where they&amp;#39;re strongest.&lt;/p&gt;
&lt;p&gt;Here are common ways to combine them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;GitOpsing Terraform&amp;quot;:&lt;/strong&gt; This approach involves setting up a dedicated Git repository to store your Terraform code. You define your infrastructure configurations in this code, and then you set up a CI/CD pipeline to use Terraform to apply changes to the infrastructure. These applications are triggered by Git merges or pull requests.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The GitOps Bridge Pattern (with caveats):&lt;/strong&gt; A common, though sometimes tricky, approach involves Terraform setting up the infrastructure and then exporting certain values (like Kubernetes cluster endpoints, IDs, or other metadata) that ArgoCD applications need. These values are often put into Kubernetes cluster secrets or annotations, which ArgoCD then uses.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Drawbacks:&lt;/strong&gt; This pattern often &lt;em&gt;requires&lt;/em&gt; using ArgoCD&amp;#39;s ApplicationSets feature, which might not be ideal for simpler setups. Crucially, it can &lt;em&gt;break Git as the single source of truth&lt;/em&gt;, because metadata used by ArgoCD comes from cluster secrets rather than directly from Git. It can also lead to bloated inline Helm values and generally doesn&amp;#39;t work with Kustomize.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved GitOps-friendly integration:&lt;/strong&gt; A more robust and truly GitOps-aligned approach involves using Terraform to directly write Kubernetes-native configuration files, such as Helm values or Kustomize overlays, into Git. You can do this using Terraform providers, like the GitHub provider, that support creating and updating files or even opening pull requests directly in a Git repository.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; This method makes sure Git remains the &lt;em&gt;clear single source of truth&lt;/em&gt; for all desired states, including application configurations. All changes go through standard Git pull request workflows, and it works perfectly with both Helm and Kustomize, so you don&amp;#39;t need complex plugins or secret injection tricks. This pattern ensures that the &lt;em&gt;desired state&lt;/em&gt; for your Kubernetes applications, like specific Helm values or Kustomize configurations, is also versioned and managed in Git, fully aligning with GitOps principles.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For many organizations, the best approach isn&amp;#39;t to pick one over the other, but to combine them strategically. Terraform sets up the stable, underlying infrastructure, and GitOps makes sure applications are continuously and automatically deployed and reconciled on top of it, always being careful to keep Git as the clear single source of truth across the entire stack.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions about GitOps and IaC in Kubernetes&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;Is GitOps a replacement for DevOps?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;No, GitOps isn&amp;#39;t a replacement for DevOps; instead, it&amp;#39;s a modern, specialized approach &lt;em&gt;within&lt;/em&gt; the broader DevOps philosophy. DevOps covers a culture and a set of practices aimed at making the software development life cycle shorter and providing continuous delivery with high-quality software. GitOps is a specific set of practices and tools, especially well-suited for Kubernetes environments, that helps achieve DevOps goals by using Git as the single source of truth. It makes deployment and operations smoother, allowing for more automation, better traceability, and faster rollbacks, all of which are central to DevOps principles. GitOps essentially applies DevOps principles like version control, collaboration, and automation directly to configuration management and infrastructure operations.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Can GitOps be applied beyond Kubernetes?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Yes, while many popular GitOps tools, like ArgoCD and Flux, are heavily designed for and integrated with Kubernetes, the core ideas of GitOps can be applied to manage any type of infrastructure. This means you&amp;#39;d need the right plugins, operators, or custom tools to enable Git-driven reconciliation for non-Kubernetes resources. Challenges when using GitOps outside of Kubernetes can include making sure different resource types are idempotent, managing the creation and deletion of non-Kubernetes assets, and handling secrets securely in various environments.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What are the common challenges when adopting GitOps?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While GitOps offers big benefits, getting started with it can come with several challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Initial Setup Complexity:&lt;/strong&gt; Setting up a GitOps workflow can be complicated at first. It requires careful planning for Git repositories, branching strategies, and proper Role-Based Access Control (RBAC).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Managing Secrets:&lt;/strong&gt; A critical security concern is how to handle sensitive information (secrets) without storing them in plain text in Git. This means you&amp;#39;ll need specialized tools like Bitnami Sealed Secrets or External Secrets Operator.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handling Large Scale Deployments:&lt;/strong&gt; As your infrastructure grows, managing configurations for many environments, applications, or across many Kubernetes clusters can get complex. Scaling GitOps tools like ArgoCD or Flux across hundreds of clusters might mean deploying multiple instances or using specialized platforms built for enterprise scale.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ensuring Consistency Across Environments:&lt;/strong&gt; While GitOps aims for consistency, keeping it consistent across diverse and numerous environments can still be a challenge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring and Observability:&lt;/strong&gt; Strong monitoring and observability tools are crucial to constantly compare the desired state with the actual state and effectively spot differences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Merge Conflicts:&lt;/strong&gt; With all changes going through Git, handling merge conflicts, especially in large teams with frequent changes, requires careful planning and good Git practices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Drift (Temporary):&lt;/strong&gt; Even though GitOps tools continuously reconcile, temporary state drift can still happen if systems fail to apply changes correctly or if there are outside, unmanaged interventions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even though GitOps really focuses on automation, successfully putting it into practice brings new, significant human-centered challenges. These include needing strict Git hygiene, fostering a highly collaborative environment, and disciplined secret management. The real success of GitOps depends not just on what the tools can do, but deeply on organizational discipline and a cultural shift towards treating Git as the central control center for all operations.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The journey from managing infrastructure by hand to using automated, codified approaches has been a huge change. Infrastructure as Code (IaC) laid the groundwork, and GitOps built on that to create a super efficient and secure way to operate Kubernetes.&lt;/p&gt;
&lt;p&gt;Traditional IaC, with its focus on defining infrastructure through code and using version control, gives you basic benefits like consistency, reusability, and fewer errors. It changed the game from giving step-by-step instructions to simply declaring what you want, making complex infrastructure setup much easier. Tools like Terraform are great at managing the underlying cloud resources and Kubernetes clusters themselves, creating a stable foundation.&lt;/p&gt;
&lt;p&gt;GitOps, as an evolution of IaC, takes these ideas further by making Git the &lt;em&gt;single source of truth&lt;/em&gt; for all your infrastructure and application configurations. Its pull-based deployment model, continuous reconciliation by agents inside the cluster, and built-in auditability offer big advantages in security, automated drift detection, and simpler rollbacks. GitOps turns Git into a dynamic control center, putting IaC into action to make sure what you want always matches what&amp;#39;s actually running. Tools like ArgoCD and Flux provide strong ways to implement this method, each with different ideas about user experience and how much you can extend them.&lt;/p&gt;
&lt;p&gt;Comparing the two shows that GitOps offers a more proactive, self-healing, and secure way to deploy to Kubernetes, especially because of its pull-based architecture and continuous reconciliation loop. While traditional IaC might rely on reactive drift detection, GitOps actively enforces the desired state, keeping configuration drift to a minimum. Plus, GitOps makes Git more than just a version control system; it turns it into a central place for all operational changes, leading to better communication and alignment across development and operations teams.&lt;/p&gt;
&lt;p&gt;For organizations managing Kubernetes, the choice isn&amp;#39;t necessarily between IaC and GitOps, but rather how to best combine their strengths. Terraform can set up the foundational Kubernetes infrastructure, while GitOps tools like ArgoCD or Flux can manage the applications and configurations deployed within those clusters. The most effective strategies involve using both where they&amp;#39;re best, always being careful to keep Git as the clear single source of truth across the entire stack.&lt;/p&gt;
&lt;p&gt;While GitOps promises a lot of automation and reliability, successfully adopting it means tackling challenges like the initial setup complexity, securely managing secrets, and keeping up good Git practices. Ultimately, the real power of GitOps isn&amp;#39;t just in what it can do technically, but in its ability to foster a disciplined, collaborative culture that embraces Git as the definitive source for all operational changes, driving consistency, security, and agility in the cloud-native world.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What is Infrastructure as Code? - IaC Explained - AWS, accessed on June 6, 2025, &lt;a href=&quot;https://aws.amazon.com/what-is/iac/&quot;&gt;https://aws.amazon.com/what-is/iac/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Deploy your first app on Kubernetes with GitOps | CNCF, accessed on June 6, 2025, &lt;a href=&quot;https://www.cncf.io/blog/2024/09/09/deploy-your-first-app-on-kubernetes-with-gitops/&quot;&gt;https://www.cncf.io/blog/2024/09/09/deploy-your-first-app-on-kubernetes-with-gitops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Is GitOps? The Complete Guide - Komodor, accessed on June 6, 2025, &lt;a href=&quot;https://komodor.com/blog/what-is-gitops-the-complete-guide/&quot;&gt;https://komodor.com/blog/what-is-gitops-the-complete-guide/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitOps Workflow vs. Traditional Workflow: What Is the Difference? - Codefresh, accessed on June 6, 2025, &lt;a href=&quot;https://codefresh.io/learn/gitops/gitops-workflow-vs-traditional-workflow-what-is-the-difference/&quot;&gt;https://codefresh.io/learn/gitops/gitops-workflow-vs-traditional-workflow-what-is-the-difference/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Argo CD? Overview &amp;amp; Tutorial - Spacelift, accessed on June 6, 2025, &lt;a href=&quot;https://spacelift.io/blog/argocd&quot;&gt;https://spacelift.io/blog/argocd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Flux CD &amp;amp; How Does It Work? [Tutorial] - Spacelift, accessed on June 6, 2025, &lt;a href=&quot;https://spacelift.io/blog/fluxcd&quot;&gt;https://spacelift.io/blog/fluxcd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Flux CD vs. Argo CD: GitOps Tools Comparison - Spacelift, accessed on June 6, 2025, &lt;a href=&quot;https://spacelift.io/blog/flux-vs-argo-cd&quot;&gt;https://spacelift.io/blog/flux-vs-argo-cd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IaC in Kubernetes: 6 Tools, Tutorial and Tips for Success - Codefresh, accessed on June 6, 2025, &lt;a href=&quot;https://codefresh.io/learn/infrastructure-as-code/iac-kubernetes/&quot;&gt;https://codefresh.io/learn/infrastructure-as-code/iac-kubernetes/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Drift Detection in Kubernetes - Komodor, accessed on June 6, 2025, &lt;a href=&quot;https://komodor.com/blog/drift-detection-in-kubernetes/&quot;&gt;https://komodor.com/blog/drift-detection-in-kubernetes/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to apply security at the source using GitOps - Sysdig, accessed on June 6, 2025, &lt;a href=&quot;https://sysdig.com/blog/gitops-iac-security-source/&quot;&gt;https://sysdig.com/blog/gitops-iac-security-source/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Hard Truth about GitOps and Database Rollbacks - Atlas, accessed on June 6, 2025, &lt;a href=&quot;https://atlasgo.io/blog/2024/11/14/the-hard-truth-about-gitops-and-db-rollbacks&quot;&gt;https://atlasgo.io/blog/2024/11/14/the-hard-truth-about-gitops-and-db-rollbacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Integrate Terraform with Argo CD for GitOps Workflows - Akuity, accessed on June 6, 2025, &lt;a href=&quot;https://akuity.io/blog/yet-another-take-on-integrating-terraform-with-argo-cd&quot;&gt;https://akuity.io/blog/yet-another-take-on-integrating-terraform-with-argo-cd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitOps Your Terraform in 4 Easy Steps | Codefresh, accessed on June 6, 2025, &lt;a href=&quot;https://codefresh.io/learn/gitops/gitops-your-terraform-in-4-easy-steps/&quot;&gt;https://codefresh.io/learn/gitops/gitops-your-terraform-in-4-easy-steps/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes Security Best Practices: Definitive Guide | CSA, accessed on June 6, 2025, &lt;a href=&quot;https://cloudsecurityalliance.org/blog/2022/03/03/kubernetes-security-best-practices-definitive-guide&quot;&gt;https://cloudsecurityalliance.org/blog/2022/03/03/kubernetes-security-best-practices-definitive-guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Infrastructure as code vs. GitOps – A real-world example - fredrkl, accessed on June 6, 2025, &lt;a href=&quot;https://fredrkl.com/blog/infrastructure-as-code-vs-gitops-a-real-world-example/&quot;&gt;https://fredrkl.com/blog/infrastructure-as-code-vs-gitops-a-real-world-example/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Infrastructure as Code</category><category>GitOps</category><category>Kubernetes</category><category>Cloud Native</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0101-gitops-vs-traditional-iac-kubernetes-deployment/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Serverless Observability: A Comprehensive Guide to AWS Lambda Monitoring</title><link>https://mkabumattar.com/blog/post/aws-lambda-observability-guide/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/aws-lambda-observability-guide/</guid><description>Master AWS Lambda monitoring with this comprehensive guide to serverless observability. Learn how CloudWatch, X-Ray, and Datadog help you track performance, troubleshoot issues, and optimize costs for your serverless applications. Get practical tips and best practices for building resilient Lambda functions.</description><pubDate>Sat, 21 Mar 2026 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;strong&gt;Introduction: Why Serverless Observability is Non-Negotiable for AWS Lambda?&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What is Serverless Computing and AWS Lambda?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Serverless computing is a big change in how we build things in the cloud. It takes away all the tricky parts of managing servers yourself. With this approach, your cloud provider automatically gives you the computing power you need, so you can just focus on writing your application code. You don&amp;#39;t have to worry about setting up servers, scaling them, keeping them running, patching them, or balancing the load, which you&amp;#39;d normally do with traditional server-based applications. What&amp;#39;s great about serverless is how fast it helps you go from an idea to a working application. You can build and get things out there really quickly.&lt;/p&gt;
&lt;p&gt;AWS Lambda is a key serverless service from Amazon Web Services. It lets you run code when certain events happen, and you don&amp;#39;t have to set up or manage any servers. Since AWS fully manages this service, they handle all the underlying infrastructure, including built-in fault tolerance and security. Because it&amp;#39;s event-driven and you only pay for what you use, your costs stay low. You&amp;#39;re not paying for servers just sitting around, which can save you money compared to traditional setups where you might over-provision resources. AWS Lambda is super flexible; people use it for all sorts of things like web applications, processing data streams, and automating batch jobs.&lt;/p&gt;
&lt;p&gt;Even though serverless promises to make things simpler by hiding the infrastructure, that very simplicity can actually make other things more complicated. When your application is made up of many small, interconnected pieces, it can feel like a black box if you don&amp;#39;t have good visibility. Plus, the cost savings you get from paying only for what you use depend on how efficiently you&amp;#39;re using things. If your functions aren&amp;#39;t optimized or they&amp;#39;re getting called unexpectedly, your bills can get surprisingly high. So, you need a deep understanding of how your application behaves across all those small, connected pieces. Good operational insight isn&amp;#39;t just nice to have; it&amp;#39;s absolutely essential if you want to get the most out of serverless.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Why is Observability Crucial for Modern Serverless Architectures?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To really get a handle on these modern, distributed systems, it&amp;#39;s important to know the difference between monitoring and observability. Monitoring is about gathering data and making reports on specific things that tell you how healthy your system is. It helps you spot unusual behavior or problems with your system&amp;#39;s state and performance, answering the &amp;quot;what&amp;quot; and &amp;quot;when&amp;quot; of an issue. Observability, on the other hand, is more like being a detective. It digs into how different parts of your distributed system talk to each other, using the data from monitoring tools to figure out &lt;em&gt;why&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt; problems happen. Observability goes beyond regular monitoring. It adds more context, historical data, and insights into how your system&amp;#39;s pieces interact.&lt;/p&gt;
&lt;p&gt;Both monitoring and observability rely on telemetry data, which usually falls into four categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Metrics:&lt;/strong&gt; These are numbers that measure system data, like how much network traffic you have or how many errors your application gets over time. Monitoring reports on these numbers, while observability tries to make them better.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Events:&lt;/strong&gt; These are specific actions that happen in your system at a certain time, like a user changing a password or an alert about too many failed login attempts. Events can trigger monitoring alerts and are really important when you&amp;#39;re investigating incidents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logs:&lt;/strong&gt; These are files generated by your software that keep a chronological record of what your system is doing, its activities, and how people are using it. Monitoring systems create these logs, and then observability tools use them for a deeper look into your system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traces:&lt;/strong&gt; These show the complete path of a single operation as it moves through different connected systems or microservices. Tracing is a key function that monitoring makes possible, and it&amp;#39;s fundamental to observability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because AWS Lambda functions are distributed, short-lived, and event-driven, traditional monitoring that focuses on servers just isn&amp;#39;t enough. In a serverless setup, one user request might go through many Lambda functions, API Gateways, databases, and other services. If an error pops up, the question isn&amp;#39;t just &amp;quot;which server broke?&amp;quot; anymore. Instead, you&amp;#39;re asking, &amp;quot;which of the hundreds or thousands of functions, in what order, talking to which services, actually caused this problem?&amp;quot;. Observability, especially with distributed tracing, works like a GPS for these complex systems. It maps out the whole request journey, from when it starts, through every function call and service interaction, helping you pinpoint the exact spot and root cause of a failure. This complete picture is super important for fixing problems faster (we call that reducing MTTR) in serverless, where everything depends on everything else and issues can show up far from where they started.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a table that sums up the main differences between monitoring and observability:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Monitoring&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Observability&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What is it?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Measuring and reporting on specific metrics within a system to ensure system health.&lt;/td&gt;
&lt;td&gt;Collecting metrics, events, logs, and traces to enable deep investigation into health concerns across distributed systems with microservice architectures.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Main Focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Collect data to identify anomalous system effects.&lt;/td&gt;
&lt;td&gt;Investigate the root cause of anomalous system effects.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Systems Involved&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Typically concerned with standalone systems.&lt;/td&gt;
&lt;td&gt;Typically concerned with multiple, disparate systems.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Traceability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited to the edges of the system.&lt;/td&gt;
&lt;td&gt;Available where signals are emitted across disparate system architectures.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System Error Findings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;what&lt;/em&gt;.&lt;/td&gt;
&lt;td&gt;The &lt;em&gt;why&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Monitoring is a really important part of observability. Good monitoring gives you the detailed metrics, events, logs, and traces that observability then uses to dig deeper into incidents. Monitoring tells you &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;what&lt;/em&gt; a system error is, while observability explains &lt;em&gt;why&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt; it happened.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Navigating the Serverless Landscape: Common Monitoring Challenges&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What Unique Monitoring Complexities Does Serverless Introduce?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The very things that make serverless appealing also bring their own set of monitoring challenges. Lambda functions don&amp;#39;t stick around long; they pop up when needed. This means traditional monitoring, which is built for long-running servers, just doesn&amp;#39;t work well. Functions quickly start, run their code, and then disappear, leaving behind only their data. This fast lifecycle makes it hard to capture a continuous state or persistent issues using old methods.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s more, breaking applications down into many small, often tiny, functions leads to something we call &amp;quot;function sprawl.&amp;quot; An application can easily have hundreds or even thousands of tiny functions running all at once. Each of these functions creates its own logs and metrics, which results in a huge and fragmented data landscape that&amp;#39;s tough to bring together and understand. This sheer volume and spread of components make it complicated to get a unified view of your system&amp;#39;s health.&lt;/p&gt;
&lt;p&gt;Debugging becomes much more complex in serverless setups. An error that starts in one function might travel through several connected services before you even see a symptom in a completely different part of the system. Finding the real problem means tracing a request&amp;#39;s path across all these different parts, which is much harder than debugging one big application. Hiding the infrastructure creates an &amp;quot;invisible infrastructure&amp;quot; problem, where traditional server-focused monitoring tools just aren&amp;#39;t relevant. You need to shift your focus from watching static resources to understanding dynamic, event-driven processes. This makes tools that can connect different event data across a distributed network of functions and services absolutely critical.&lt;/p&gt;
&lt;p&gt;Another challenge comes from Lambda functions being &amp;quot;stateless&amp;quot; and how that affects managing connections. Lambda containers often get recycled, meaning you can&amp;#39;t hold onto information at the container level. This makes it tough to keep persistent connections, like database connection pools. While it&amp;#39;s a good idea to use keep-alive directives to help with connection errors, the basic problem of managing resources that need to hold onto information in an environment that doesn&amp;#39;t hold onto information is still there.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Do Cold Starts Impact Performance and Observability?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;A &amp;quot;cold start&amp;quot; is the delay you hit when a new instance of a Lambda function starts up for the first time after being idle, or when traffic increases, or you deploy a new version. This startup process involves downloading the function&amp;#39;s code, setting up its environment, and running any initial code.&lt;/p&gt;
&lt;p&gt;Cold starts directly affect &lt;strong&gt;performance&lt;/strong&gt; and, in turn, how users experience your application, especially for things that need to be fast, like user-facing apps. Even a few seconds of delay can make your app feel slow and give users a bad experience. Several things influence how long a cold start takes. The programming language runtime plays a big part; for example,.NET or Java functions usually have longer cold starts compared to those written in Python, Node.js, or Go. Also, if you connect a Lambda function to a Virtual Private Cloud (VPC), it can add another 10 seconds or so of delay because it takes time to attach an Elastic Network Interface (ENI).&lt;/p&gt;
&lt;p&gt;Observability is super important for dealing with cold starts. Watching cold start times through tools like CloudWatch Logs and AWS X-Ray is essential. It helps you find functions that are often experiencing these delays and need some tuning. While we often talk about cold starts as a performance issue, they also directly show how responsive your application is and how much it costs. Lots of cold starts mean you&amp;#39;re not using resources efficiently, because functions are repeatedly starting up unnecessarily. By monitoring these rates, your team can fine-tune memory allocation (which also affects how much CPU a function gets) or use strategies like Provisioned Concurrency. These actions directly lead to better responsiveness and potentially lower overall costs by cutting down on wasted startup time. This shows how observability data gives you practical insights for both performance and money savings.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Is Cost Management a Hidden Challenge in Serverless?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;People often praise serverless computing for being cost-effective, especially its pay-per-use billing model. But here&amp;#39;s the hidden challenge: costs can shoot up fast if you&amp;#39;re not careful. Because you pay for every time a function runs and for the resources it uses during that run (even if there are errors), inefficient code or unexpected traffic can lead to surprisingly high bills.&lt;/p&gt;
&lt;p&gt;A big risk in serverless environments is what we call &amp;quot;wallet attacks.&amp;quot; This is when Distributed Denial of Service (DDoS) attacks or accidental loops where functions keep calling themselves can trigger massive, uncontrolled scaling. The result? Huge and unexpected charges. While this automatic scaling is great for handling real demand, it becomes a financial weak spot when you&amp;#39;re dealing with bad or erroneous traffic.&lt;/p&gt;
&lt;p&gt;Always-on observability is key for managing costs well. Watching invocation counts, how long functions run, and how much memory they use is crucial for understanding your spending patterns and finding places to save money. AWS Cost Anomaly Detection uses machine learning to keep an eye on your costs and usage, which can help you spot unusual activity, though it might have a delay of up to 24 hours. In serverless, resource consumption and cost are directly linked. This means observability tools aren&amp;#39;t just for technical performance; they&amp;#39;re also for financial control. Without clear visibility into these numbers, you&amp;#39;re vulnerable to sudden cost spikes from bad code, wrong settings, or malicious activity. Observability acts as a &amp;quot;financial safety net,&amp;quot; giving you the data you need to control costs, use resources wisely, and avoid going over budget. It&amp;#39;s a critical tool for financial operations (FinOps) in the serverless world.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;AWS Native Powerhouses: CloudWatch for Lambda Monitoring&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;How Do CloudWatch Metrics Provide Essential Insights into Lambda Performance?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Amazon CloudWatch is the main monitoring and management service in the AWS world. It automatically gathers operational data like logs and metrics from various AWS services, including your Lambda functions. This centralized collection gives you instant, &amp;quot;out-of-the-box&amp;quot; visibility into how your functions are doing without a lot of manual setup. That&amp;#39;s a big plus for getting things deployed quickly and for initial checks. However, while these metrics tell you &lt;em&gt;what&amp;#39;s&lt;/em&gt; happening (like lots of errors or long run times), they don&amp;#39;t automatically tell you &lt;em&gt;why&lt;/em&gt;. This shows a basic gap in getting full observability: metrics are a great start for monitoring, but you need to add logs and traces for a thorough root cause analysis.&lt;/p&gt;
&lt;p&gt;Here are some key built-in metrics CloudWatch automatically collects for Lambda functions:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Metric Name&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Significance&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Invocations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The number of times a Lambda function is called.&lt;/td&gt;
&lt;td&gt;Shows demand and usage patterns; high counts might mean you need to scale up other services or adjust how many functions can run at once.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Errors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The number of times a function call resulted in an error (like unhandled exceptions, runtime problems, timeouts, or configuration issues).&lt;/td&gt;
&lt;td&gt;Tells you about your function&amp;#39;s reliability and stability; super important for finding problems.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Duration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How long (in milliseconds) the Lambda function code runs, from start to finish.&lt;/td&gt;
&lt;td&gt;Essential for making your function faster and managing costs, since you pay based on how long it runs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Throttles&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How many times Lambda rejected function calls because you hit your concurrency limits.&lt;/td&gt;
&lt;td&gt;Points to bottlenecks in how many functions can run at once and how that might affect your application&amp;#39;s responsiveness.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ConcurrentExecutions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The number of Lambda function instances running at the same time.&lt;/td&gt;
&lt;td&gt;Shows how many functions are running concurrently and helps you manage function scaling and limits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max Memory Used&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The most memory (in MB) your function used during a single run.&lt;/td&gt;
&lt;td&gt;Crucial for optimizing memory allocation, because giving your function more memory also gives it more CPU, which affects both performance and cost.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Looking at the &lt;code&gt;Max Memory Used&lt;/code&gt; field, which you can see in the &lt;code&gt;REPORT&lt;/code&gt; entry for each function call in CloudWatch Logs, is especially helpful for optimizing memory allocation and, by extension, how much CPU a function gets. Tools like the open-source AWS Lambda Power Tuning project can help you find the best memory setup.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Unlocking Deeper Understanding with CloudWatch Logs and Logs Insights&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;AWS Lambda automatically captures logs for all function invocations and sends them to CloudWatch Logs, as long as your function&amp;#39;s execution role has the right permissions. By default, these logs go into log groups specific to each function, usually named &lt;code&gt;/aws/lambda/&amp;lt;function-name&amp;gt;&lt;/code&gt;. While metrics give you symptoms, logs are like the detailed &amp;quot;crime scene&amp;quot; evidence of what happened during a function&amp;#39;s run.&lt;/p&gt;
&lt;p&gt;CloudWatch Logs Insights is a powerful, interactive tool that helps you analyze this log data. It turns raw, often huge, log streams into data you can easily search. This lets engineers dig into specific &lt;code&gt;requestIds&lt;/code&gt; and understand the sequence of events that led to an error or a slowdown. This ability is critical for moving beyond &lt;em&gt;what&lt;/em&gt; happened to &lt;em&gt;why&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt;, forming the backbone of effective serverless debugging.&lt;/p&gt;
&lt;p&gt;Here are some tips for effective log analysis:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Start Simple:&lt;/strong&gt; Begin with basic queries looking for error messages, then make them more specific.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Group by Time:&lt;/strong&gt; Use time intervals to spot trends or issues that keep coming back.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filter Smartly:&lt;/strong&gt; Narrow down your logs to focus on specific error types or serious problems. For example, a query like filter &lt;code&gt;@message LIKE /ERROR/ or @message LIKE /Task timed out/&lt;/code&gt; can help you find function calls with errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Structured Logging:&lt;/strong&gt; It&amp;#39;s a good idea to use structured JSON logging, including key-value pairs like &lt;code&gt;timestamp&lt;/code&gt;, &lt;code&gt;level&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;, and &lt;code&gt;AWSrequestId&lt;/code&gt;. This makes it much easier to filter and analyze within Logs Insights.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s an example of a CloudWatch Logs Insights query to find errors:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;filter @message LIKE /ERROR/ or @message LIKE /Task timed out/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And if you want to dig into a specific request:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;filter (@message LIKE /ERROR/ or @message LIKE /Task timed out/) and @requestId = &amp;quot;your-request-id&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Setting Up Proactive Alerts with CloudWatch Alarms: Your First Line of Defense&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;CloudWatch Alarms help you catch problems early by letting you set thresholds on important Lambda metrics. When a metric goes past a certain point, an alarm can go off, acting as your first line of defense. For instance, you can set an alarm based on how long you expect a function to run to spot bottlenecks or delays.&lt;/p&gt;
&lt;p&gt;You can connect these alarms to Amazon SNS (Simple Notification Service) topics, which then send out alerts through different ways, like email, SMS, or even integrations with chat services like Slack. This makes sure the right teams get notified quickly about critical issues.&lt;/p&gt;
&lt;p&gt;Beyond just sending notifications, CloudWatch Alarms can also trigger other Lambda functions when an alarm state is reached. This means you can set up automatic fixes, like automatically giving more memory to a struggling function or rolling back a bad deployment. This capability helps you recover faster (that&amp;#39;s MTTR) and takes a load off your team, pushing serverless setups towards being more resilient and autonomous. So, alarms are a crucial link that takes you from just reacting to problems to proactively fixing them automatically.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of an AWS CLI command to set up a CloudWatch alarm for a high error rate:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws cloudwatch put-metric-alarm --alarm-name &amp;quot;HighErrorRate&amp;quot; \
  --metric-name Errors --namespace AWS/Lambda --statistic Sum \
  --period 60 --threshold 5 --comparison-operator GreaterThanThreshold \
  --dimensions Name=FunctionName,Value=your-function-name \
  --evaluation-periods 1 --alarm-actions arn:aws:sns:region:account-id:your-sns-topic
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Visualizing Your Serverless Health with CloudWatch Dashboards&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In complex serverless environments with many distributed parts, having one clear, combined view of how things are running is incredibly valuable. CloudWatch Dashboards give you customizable web-based interfaces that offer a unified overview of various metrics, logs, and alarms across your AWS resources. These dashboards are like your &amp;quot;control center,&amp;quot; letting your teams see how different pieces of data connect at a glance, spot trends, and quickly check the overall system status.&lt;/p&gt;
&lt;p&gt;CloudWatch offers both automatic dashboards, which AWS sets up for common services like Lambda, and manual dashboards, which give you the flexibility to create custom views tailored to your specific monitoring needs. Dashboards support various types of widgets, including line charts for comparing metrics, number widgets for showing single values, log tables for raw log data, and alarm status widgets for a quick look at your alerts. The ability to share these dashboards with your team and other stakeholders helps everyone stay on the same page operationally, makes it easier to handle incidents, and builds a shared understanding of your application&amp;#39;s health.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Gaining Enhanced Visibility with CloudWatch Lambda Insights&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;CloudWatch Lambda Insights is a special feature that makes it easier to gather, see, and dig into detailed performance metrics, errors, and logs just for your Lambda functions. This service acts like a higher-level, managed monitoring agent specifically for Lambda functions. By taking away the hassle of manual setup and offering pre-curated performance metrics and visualizations, it makes it much simpler to get deep insights into performance.&lt;/p&gt;
&lt;p&gt;When you turn it on, Lambda Insights reports eight specific metrics per function, and each function invocation sends about 1 KB of log data to CloudWatch. This detailed data helps you do deeper performance analysis. You can view metrics across many Lambda functions in a &amp;quot;Multi-function&amp;quot; view or zoom in on a single function for granular performance data, including error rates, CPU, memory, and network usage.&lt;/p&gt;
&lt;p&gt;Lambda Insights is built on AWS Lambda Extensions, which let diagnostic tools integrate deeply into the Lambda execution environment and capture information throughout the function&amp;#39;s lifecycle. The service works on a pay-per-use model, meaning you only pay for the metrics and logs it reports, with no minimum fees. This makes it cost-effective for functions that get called at different rates. This shows how AWS is working to provide more integrated, &amp;quot;observability with almost no setup&amp;quot; for their serverless offerings, making advanced troubleshooting more accessible to more people.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Tracing the Journey: AWS X-Ray for Distributed Observability&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;How Does X-Ray Provide End-to-End Tracing for Lambda Functions?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;AWS X-Ray is a service that gives you a complete picture of how requests move through your applications. It helps developers and operators understand how their Lambda functions interact with other AWS services and find performance bottlenecks. In a serverless setup, one user request can go through many Lambda functions, API Gateways, databases, and other services. Without a clear map, trying to debug something that crosses all these boundaries is super tough.&lt;/p&gt;
&lt;p&gt;X-Ray solves this by collecting data about requests as they travel through different resources in an application. It processes this trace data to create a service map, which visually shows all the connected services and how they relate, along with searchable summaries of traces. This service map is like a GPS for your serverless microservices. It gives you a visual representation of the entire request journey and helps you pinpoint the exact location and cause of failures or slow spots. This is essential for understanding how services depend on each other and for turning chaotic distributed systems into understandable flows.&lt;/p&gt;
&lt;p&gt;Lambda functions work seamlessly with X-Ray. Lambda runs the X-Ray daemon and automatically records segments with details about calling and running the function. X-Ray also supports tracing applications that are event-driven, like those using Amazon SQS (Simple Queue Service) and Amazon SNS (Simple Notification Service). This gives you end-to-end visibility of requests as they&amp;#39;re queued and processed by downstream Lambda functions, connecting traces from where they start to where they end up.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Active vs. PassThrough: Choosing the Right Tracing Strategy for Your Application&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Lambda supports two different tracing modes for X-Ray: &lt;code&gt;Active&lt;/code&gt; and &lt;code&gt;PassThrough&lt;/code&gt;. Having these two modes means you can be smart about your observability, because not every tracing need is the same.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Active Tracing Mode:&lt;/strong&gt; When you turn on &lt;code&gt;Active&lt;/code&gt; tracing, Lambda automatically creates trace segments for function invocations and sends them to X-Ray. If an upstream service doesn&amp;#39;t decide whether to sample, Lambda samples requests at a rate of one request per second plus 5% of additional requests. If an upstream service specifically says &lt;em&gt;not&lt;/em&gt; to sample, Lambda respects that choice. This mode gives you a full picture of how your Lambda function is performing and behaving, making it especially useful for getting detailed insights for troubleshooting and making things better.
To enable active tracing for your Lambda function using the AWS CLI, you can use this command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws lambda update-function-configuration --function-name YOUR_FUNCTION_NAME --tracing-config Mode=Active
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PassThrough Tracing Mode:&lt;/strong&gt; In &lt;code&gt;PassThrough&lt;/code&gt; mode, Lambda simply passes the tracing context along to downstream services without creating its own trace segments or subsegments for the function invocation. This means that even if an incoming call includes a decision to sample the request, Lambda won&amp;#39;t generate traces for the function itself. This mode is valuable for saving money or when downstream services are responsible for making their own tracing decisions. It gives you more control and you know what to expect from your tracing setup, letting you optimize your tracing strategy and manage overhead. &lt;br&gt; To configure &lt;code&gt;PassThrough&lt;/code&gt; tracing for your Lambda function using the AWS CLI, you can use this command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws lambda update-function-configuration --function-name YOUR_FUNCTION_NAME --tracing-config Mode=PassThrough
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The choice between &lt;code&gt;Active&lt;/code&gt; and &lt;code&gt;PassThrough&lt;/code&gt; mode is a strategic decision. You&amp;#39;re trying to find a good balance between seeing everything and managing costs. You can turn on tracing selectively for important parts of your application or for functions with complex dependencies, instead of just tracing everything. This way, you focus your efforts where you&amp;#39;ll get the most operational benefits, rather than adding unnecessary overhead or cost.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a table that sums up the main differences between AWS X-Ray tracing modes for Lambda:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Mode&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Behavior&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Sampling Decision&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Use Case&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lambda automatically creates trace segments and sends them to X-Ray.&lt;/td&gt;
&lt;td&gt;If no upstream decision, samples 1 request/sec + 5% further. Respects upstream &amp;quot;no sample&amp;quot; decisions.&lt;/td&gt;
&lt;td&gt;Complete visibility into function performance and behavior.&lt;/td&gt;
&lt;td&gt;Comprehensive insights for troubleshooting and optimization.&lt;/td&gt;
&lt;td&gt;Higher cost due to increased trace generation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PassThrough&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lambda propagates tracing context to downstream services without creating its own segments.&lt;/td&gt;
&lt;td&gt;Respects incoming tracing context; does &lt;em&gt;not&lt;/em&gt; create segments even if incoming request is sampled.&lt;/td&gt;
&lt;td&gt;Cost optimization; when downstream services handle tracing decisions; propagating context without local tracing overhead.&lt;/td&gt;
&lt;td&gt;Reduced tracing costs and overhead; greater control over where traces are generated.&lt;/td&gt;
&lt;td&gt;Less granular visibility into the specific Lambda function&amp;#39;s execution.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;&lt;strong&gt;Integrating X-Ray with Your Lambda Functions: A Practical Guide&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Turning on X-Ray tracing for Lambda functions is pretty easy. You can set up active tracing right from the Lambda console. Just go to your function&amp;#39;s &amp;quot;Configuration&amp;quot; tab, then &amp;quot;Monitoring and operations tools,&amp;quot; and turn on &amp;quot;Active tracing&amp;quot; under the AWS X-Ray section.&lt;/p&gt;
&lt;p&gt;For even more detailed information within your function&amp;#39;s code, developers can include the X-Ray SDK with their Lambda function. The X-Ray SDK lets you instrument outgoing calls to other AWS services or external APIs, and you can also add custom notes and extra data to subsegments. This gives you really specific details about what&amp;#39;s happening inside your function&amp;#39;s execution. X-Ray SDKs are available for various runtimes, including Go, Java, Node.js, and Python.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s important to remember one limitation: while the X-Ray SDK lets you create subsegments and add notes and metadata to them, your function&amp;#39;s code can&amp;#39;t change the main segment that the Lambda service creates.&lt;/p&gt;
&lt;p&gt;Adding the X-Ray SDK and custom instrumentation means there&amp;#39;s some extra work, which might make your deployment package a bit bigger or have a tiny impact on runtime. The best practice of only turning on X-Ray for critical functions or those with complex dependencies acknowledges this trade-off. This approach highlights that observability, while crucial, should be a smart investment. You want to focus your efforts where you&amp;#39;ll get the most operational benefits, rather than just tracing everything, which might add unnecessary overhead or cost.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Beyond Native: Leveraging Datadog for Comprehensive Serverless Monitoring&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What Enhanced Capabilities Does Datadog Offer for AWS Lambda Observability?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While AWS&amp;#39;s native tools give you strong monitoring capabilities, third-party solutions like Datadog offer even better features for complete serverless observability. This is especially helpful if you&amp;#39;re using multiple clouds or a mix of cloud and on-premises systems. Datadog aims to give you end-to-end visibility into your serverless applications, with the goal of helping you find and fix problems faster (that&amp;#39;s MTTD and MTTR).&lt;/p&gt;
&lt;p&gt;Datadog stands out because it offers a single platform that brings together and connects all your metrics, traces, and logs from every function run into one clear view. This &amp;quot;one place to see everything&amp;quot; approach makes it less complicated to manage different monitoring tools and gives you a consistent view across your whole tech stack. That&amp;#39;s a big advantage for large, complex organizations that might be using different cloud providers or have their own on-premises infrastructure.&lt;/p&gt;
&lt;p&gt;The platform gives you details down to each function, helping you pinpoint exactly which resources are causing errors, high latency, or cold starts in your serverless environments. Datadog also offers smarter alerting, including real-time alerts for memory, timeout, and concurrency metrics, which helps prevent bad experiences for your end-users. Its &amp;quot;Serverless Warnings&amp;quot; feature automatically suggests ways to fix errors and performance problems, using CloudWatch metrics and Lambda REPORT log lines.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s more, Datadog can gather custom business metrics right from your functions. This lets you connect them with health metrics and see them on customizable dashboards. This capability helps break down data silos and gives development, operations, and business teams one unified source of truth. Datadog also makes setup simple with &amp;quot;observability with almost no setup&amp;quot; through integrations with AWS SAM, Serverless Framework, and AWS CDK.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Does Datadog Unify Metrics, Logs, and Traces for a Holistic View?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Datadog&amp;#39;s way of bringing together metrics, logs, and traces for AWS Lambda involves a thorough way to collect data. Its Lambda extension gathers logs through CloudWatch, and then adds traces, better metrics, and custom metrics from the Datadog Lambda Library. This method ensures that a rich variety of telemetry data gets into the platform.&lt;/p&gt;
&lt;p&gt;A cool feature is how Datadog automatically grabs function requests and responses for every time your function runs. This gives you crucial information about the data payload, which can really speed up troubleshooting by providing key context around why a function failed.&lt;/p&gt;
&lt;p&gt;The real power of Datadog isn&amp;#39;t just in collecting these different data streams, but in smartly connecting them across your whole application. Instead of manually piecing together information from separate CloudWatch dashboards, Logs Insights queries, and X-Ray traces, Datadog&amp;#39;s platform automatically links these signals to a specific request or function invocation. This &amp;quot;intelligent correlation&amp;quot; significantly speeds up troubleshooting by presenting a clear story of what went wrong. You can spot critical application issues and jump to relevant traces or logs with just one click, which makes it easier for engineers to understand and helps you fix problems faster (MTTR). This unified visibility lets you fully understand an individual customer request, from when it started through all its associated logs and metrics, giving you a complete picture of your application&amp;#39;s health.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Mastering Serverless Observability: Best Practices for AWS Lambda&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;Why is a Multi-Layered Monitoring Approach Essential?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For complete observability in serverless environments, just using one tool isn&amp;#39;t enough. Metrics, logs, and traces each offer a unique way to look at system behavior. They provide different pieces of the puzzle that, when put together, give you the whole picture. Metrics offer aggregated numbers, answering &amp;quot;how many errors?&amp;quot; Logs give you granular event details, explaining &amp;quot;what happened during this specific error?&amp;quot; Traces map the request flow across distributed components, revealing &amp;quot;where did the error propagate?&amp;quot; No single signal tells the full story.&lt;/p&gt;
&lt;p&gt;So, a multi-layered approach is crucial. This means using the combined strengths of AWS native tools CloudWatch for basic metrics and logs, and X-Ray for distributed tracing alongside potentially third-party solutions like Datadog for advanced, unified insights in complex or multi-cloud environments. This shift from thinking about individual tool capabilities to the combined value of different types of telemetry is fundamental to effective serverless observability. It lets you do both high-level health checks and deep root cause analysis.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Can You Optimize Lambda Performance Through Continuous Observability?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Observability isn&amp;#39;t just a reactive tool for debugging; it works as a proactive &amp;quot;way to make things better&amp;quot; for serverless efficiency. By always watching performance metrics and connecting them with traces, your teams get insights from data to make small, continuous improvements.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adjusting Memory and CPU:&lt;/strong&gt; Testing performance with different memory settings is crucial, because giving your function more memory also gives it more CPU. Watching the &lt;code&gt;Max Memory Used&lt;/code&gt; field in CloudWatch &lt;code&gt;REPORT&lt;/code&gt; entries helps you fine-tune memory allocation, leading to the best performance and cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setting the Right Timeout:&lt;/strong&gt; It&amp;#39;s important to load test your Lambda functions to figure out the best timeout value, especially when functions make network calls to other services that might not scale as well as Lambda.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dealing with Cold Starts:&lt;/strong&gt; Observability data helps you come up with strategies to reduce cold starts. This includes using Provisioned Concurrency to keep function instances warm choosing efficient runtimes like Node.js, Python, or Go and using community solutions like Lambda Warmer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Finding Bottlenecks:&lt;/strong&gt; AWS X-Ray is incredibly valuable for tracing request flows to find performance bottlenecks, like slow parts of your code, inefficient database queries, or slow external API calls. Analyzing complete traces helps you target your optimizations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smart Caching:&lt;/strong&gt; Using caching can significantly cut down execution times and make things faster. This includes using Lambda Layers to store dependencies across functions, and application-level caching with services like Amazon ElastiCache for data you often request.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reusing the Execution Environment:&lt;/strong&gt; Initializing SDK clients and database connections outside your function&amp;#39;s main handler and caching static assets locally in the &lt;code&gt;/tmp&lt;/code&gt; directory can make things faster and reduce runtime costs. This is because subsequent function calls can reuse these resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s an example of how you might optimize a slow database call by using batch queries instead of single queries:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Before optimization: Single database query per request
# results = db.query(&amp;quot;SELECT * FROM users WHERE id = %s&amp;quot;, user_id)

# After optimization: Use batch queries
results = db.query(&amp;quot;SELECT * FROM users WHERE id IN (%s)&amp;quot;, batch_of_user_ids)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&amp;#39;s a simple example of using Amazon ElastiCache for caching in a Lambda function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import redis

redis_client = redis.StrictRedis(host=&amp;#39;my-redis-cluster&amp;#39;, port=6379, db=0)

def lambda_handler(event, context):
    cache_key = &amp;quot;some-key&amp;quot;
    cached_value = redis_client.get(cache_key)

    if cached_value:
        return cached_value
    else:
        # Fetch from the source, then cache the result
        result = fetch_from_database() # Assume this function fetches data
        redis_client.set(cache_key, result)
        return result
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Ensuring Cost Efficiency with Smart Monitoring Strategies&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In a serverless environment, every function call and resource used directly adds to your cost. This creates a direct &amp;quot;financial feedback loop,&amp;quot; where bad code or unoptimized settings immediately hit your budget. Observability gives you the data you need to spot these inefficiencies and potential &amp;quot;wallet attacks&amp;quot;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Always Watching Your Usage:&lt;/strong&gt; Closely monitoring invocation counts, how long functions run, and memory usage is critical for understanding your spending patterns and finding places to save money.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setting Resource Limits:&lt;/strong&gt; Setting Lambda Concurrent Execution Limits and appropriate function timeouts is essential to prevent unexpectedly huge bills from traffic spikes or recursive calls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cleaning Up Unused Functions:&lt;/strong&gt; Regularly deleting Lambda functions you&amp;#39;re no longer using stops them from needlessly counting against deployment package size limits and costing you money.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spotting Unusual Costs:&lt;/strong&gt; Using services like AWS Cost Anomaly Detection, which uses machine learning to constantly watch costs and usage, can help you spot unusual activity in your account, cutting down on false alerts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By using observability data, your teams can proactively make functions better, set limits, and spot unusual activity. This turns observability into a critical financial management tool that directly helps you save money and predict costs.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Integrating Observability into Your Development Lifecycle: Shift Left!&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Making monitoring and observability a part of your development process from the start, not something you think about later, is crucial for sustainable serverless development. This &amp;quot;shift left&amp;quot; approach makes sure your applications are inherently &amp;quot;built to be observable,&amp;quot; making them easier to debug, optimize, and secure once they&amp;#39;re deployed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setting Up Monitoring Early:&lt;/strong&gt; Developers should include custom CloudWatch metrics and turn on X-Ray traces when they create new Lambda functions. This early setup ensures you capture the necessary data from the very beginning.
Here&amp;#39;s an example of how you might add a custom metric in your Python Lambda function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import boto3

cloudwatch = boto3.client(&amp;#39;cloudwatch&amp;#39;)

def lambda_handler(event, context):
    # Custom metric: User signups
    cloudwatch.put_metric_data(
        Namespace=&amp;#39;MyApp&amp;#39;,
        MetricData=
    )
    # Continue with the rest of the Lambda function logic
    return {
        &amp;#39;statusCode&amp;#39;: 200,
        &amp;#39;body&amp;#39;: &amp;#39;Function executed successfully!&amp;#39;
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Checking and Adjusting Regularly:&lt;/strong&gt; You should regularly review and update your monitoring configurations, including CloudWatch Log retention periods, alert thresholds, custom metrics, and X-Ray sampling rates, as your application changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automatic Error Handling:&lt;/strong&gt; Setting up strong error handling, like using dead-letter queues to catch failed asynchronous calls and adding custom retry logic for synchronous calls, is vital for resilience.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Making Functions Idempotent:&lt;/strong&gt; Writing Lambda functions that produce the same result no matter how many times they&amp;#39;re called with the same input is a key part of building resilient distributed systems. It helps them gracefully handle duplicate events.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don&amp;#39;t Let Functions Call Themselves Recursively:&lt;/strong&gt; You should design functions to avoid calling themselves or processes that could lead to accidental recursive calls. This can result in huge numbers of function calls and increased costs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This proactive approach cuts down on the significant cost and complexity of trying to add observability later in the process. It also helps developers take direct responsibility for the operational health and performance of their serverless functions from day one, leading to more sustainable and resilient serverless applications.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions (FAQs) about AWS Lambda Monitoring&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What&amp;#39;s the best way to monitor cold starts?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;To effectively monitor cold starts, you&amp;#39;ll want to use CloudWatch Logs and AWS X-Ray. These services help you find functions that are experiencing long cold start times, especially those that aren&amp;#39;t called very often. For critical functions that need to be fast, using Provisioned Concurrency is a smart way to keep instances warm and reduce those startup delays. Also, choosing runtimes like Node.js, Python, or Go can help, as they generally have shorter cold start durations. For functions that aren&amp;#39;t as critical, you might look into community solutions like Lambda Warmer to help keep them ready.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example AWS CLI command to enable Provisioned Concurrency for a Lambda function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws lambda put-provisioned-concurrency-config \
  --function-name my-function \
  --provisioned-concurrent-executions 5 \
  --qualifier $LATEST
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can I reduce my Lambda monitoring costs?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cutting down on Lambda monitoring costs involves optimizing how your functions use resources and being smart about your monitoring tools. Make sure your function&amp;#39;s duration and memory allocation are optimized, because these directly affect your bill. Delete any Lambda functions you&amp;#39;re no longer using so they don&amp;#39;t needlessly count against your deployment limits. Set appropriate Lambda Concurrent Execution Limits and timeout values to prevent unexpectedly huge bills from unexpected traffic or recursive loops. For AWS X-Ray, think about using PassThrough tracing mode when full end-to-end visibility isn&amp;#39;t absolutely critical, as this reduces how many traces are generated and their associated costs. Be aware of the costs for services like CloudWatch Lambda Insights, which charges based on usage, meaning you only pay for the metrics and logs it reports.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Should I use native AWS tools or a third-party solution?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;A multi-layered approach is generally the way to go for complete serverless observability. AWS&amp;#39;s native tools, like CloudWatch (for metrics, logs, and alarms) and X-Ray (for distributed tracing), give you foundational, deeply integrated, and detailed observability capabilities. Third-party solutions like Datadog offer a unified platform, advanced features like automated warnings and connecting business metrics, and crucial cross-cloud visibility for hybrid or multi-cloud environments. The best choice really depends on how complex your application is, your budget, the tools you&amp;#39;re already using, and your team&amp;#39;s expertise. Often, using a mix of native and third-party tools gives you the most complete and actionable view of your system&amp;#39;s health.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do I set up alerts for critical Lambda errors?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;To set up alerts for critical Lambda errors, go to CloudWatch and create an alarm for your Lambda function&amp;#39;s &amp;#39;Errors&amp;#39; metric. Configure the alarm to go off when the error count goes above a certain threshold over a specific time. Link this alarm to an Amazon SNS topic to send notifications via email, SMS, or integrated chat services. For more advanced alerting, use metric filters in CloudWatch Logs to spot specific error patterns within your function logs. You might even consider automating responses to these alarms by triggering another Lambda function to perform self-remediation actions.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the most important metrics to track for Lambda functions?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;The most important metrics to track for Lambda functions give you critical insights into performance, reliability, and cost. These include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Invocations:&lt;/strong&gt; This tells you how often the function is called.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Errors:&lt;/strong&gt; This shows the number of failed function calls, including code and runtime errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Duration:&lt;/strong&gt; This measures how long the function runs, which is directly tied to performance and cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Throttles:&lt;/strong&gt; This indicates when you&amp;#39;re hitting concurrency limits, pointing to potential bottlenecks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ConcurrentExecutions:&lt;/strong&gt; This reflects how many functions are running at the same time, showing concurrent usage levels.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Max Memory Used:&lt;/strong&gt; This helps you optimize memory allocation, which affects CPU availability and cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cold Start Times:&lt;/strong&gt; (You get this from logs/traces) This is essential for understanding how initialization delays affect user experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;Conclusion: Building Resilient and Optimized Serverless Applications&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Complete observability isn&amp;#39;t just helpful; it&amp;#39;s absolutely essential for serverless applications to succeed. That&amp;#39;s because they&amp;#39;re inherently distributed, short-lived, and event-driven. While hiding the infrastructure makes things simpler operationally, it also makes it harder to understand how your application behaves across all its many interconnected parts. This means we need to move away from traditional server-focused monitoring to a more holistic, investigative approach that includes metrics, logs, and traces.&lt;/p&gt;
&lt;p&gt;AWS&amp;#39;s native tools, like CloudWatch, give you the basic capabilities for collecting metrics and logs. They let you set up proactive alerts and see everything in one place through dashboards and special insights like Lambda Insights. AWS X-Ray works with this by offering powerful distributed tracing, which is crucial for navigating complex microservice interactions and finding performance bottlenecks across different services. Beyond what AWS offers, third-party solutions like Datadog provide a unified layer that brings together different telemetry data from various sources into one view. This is especially useful for multi-cloud or hybrid environments.&lt;/p&gt;
&lt;p&gt;Constantly analyzing observability data acts like a powerful &amp;quot;way to make things better&amp;quot; for serverless efficiency. It lets you continuously fine-tune memory allocation, code efficiency, and strategically use features like provisioned concurrency to boost performance and reduce cold starts. What&amp;#39;s more, observability acts as a critical &amp;quot;financial safety net.&amp;quot; It gives you the data you need to watch your usage, control costs, and spot unusual activity, directly helping you save money and predict your spending.&lt;/p&gt;
&lt;p&gt;Ultimately, strong serverless observability empowers teams to build applications that are more resilient, cost-efficient, and perform better. By making observability a part of your development process early on, using a multi-layered monitoring approach, and continuously using data to make things better (both performance and cost-wise), organizations can truly unlock the full potential of serverless. This turns operational challenges into chances for innovation and efficiency.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;5 Serverless Challenges of DevOps Teams and How to Overcome ..., accessed on June 7, 2025, &lt;a href=&quot;https://devops.com/5-serverless-challenges-of-devops-teams-and-how-to-overcome-them/&quot;&gt;https://devops.com/5-serverless-challenges-of-devops-teams-and-how-to-overcome-them/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Lambda: Serverless Computing Explained - AWS, accessed on June 7, 2025, &lt;a href=&quot;https://aws.amazon.com/awstv/watch/64bb50cff05/&quot;&gt;https://aws.amazon.com/awstv/watch/64bb50cff05/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;aws.amazon.com, accessed on June 7, 2025, &lt;a href=&quot;https://aws.amazon.com/awstv/watch/64bb50cff05/#:~:text=AWS%20Lambda%2C%20a%20serverless%20compute,into%20a%20modern%20production%20application.&quot;&gt;https://aws.amazon.com/awstv/watch/64bb50cff05/#:~:text=AWS%20Lambda%2C%20a%20serverless%20compute,into%20a%20modern%20production%20application.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Serverless Computing – Amazon Web Services - AWS, accessed on June 7, 2025, &lt;a href=&quot;https://aws.amazon.com/serverless/&quot;&gt;https://aws.amazon.com/serverless/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Observability vs Monitoring - Difference Between Data-Based ... - AWS, accessed on June 7, 2025, &lt;a href=&quot;https://aws.amazon.com/compare/the-difference-between-monitoring-and-observability/&quot;&gt;https://aws.amazon.com/compare/the-difference-between-monitoring-and-observability/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;aws.amazon.com, accessed on June 7, 2025, &lt;a href=&quot;https://aws.amazon.com/compare/the-difference-between-monitoring-and-observability/#:~:text=With%20monitoring%20systems%2C%20you%20can,between%20hundreds%20of%20service%20components.&quot;&gt;https://aws.amazon.com/compare/the-difference-between-monitoring-and-observability/#:~:text=With%20monitoring%20systems%2C%20you%20can,between%20hundreds%20of%20service%20components.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ask the Expert: AWS serverless challenges and how to overcome ..., accessed on June 7, 2025, &lt;a href=&quot;https://www.jeffersonfrank.com/insights/aws-serverless-challenges-and-tips/&quot;&gt;https://www.jeffersonfrank.com/insights/aws-serverless-challenges-and-tips/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Streamlining trace sampling behavior for AWS Lambda functions ..., accessed on June 7, 2025, &lt;a href=&quot;https://aws.amazon.com/blogs/compute/streamlining-trace-sampling-behavior-for-aws-lambda-functions-with-aws-x-ray/&quot;&gt;https://aws.amazon.com/blogs/compute/streamlining-trace-sampling-behavior-for-aws-lambda-functions-with-aws-x-ray/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Visualize Lambda function invocations using AWS X-Ray, accessed on June 7, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Lambda and AWS X-Ray - AWS Documentation, accessed on June 7, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/xray/latest/devguide/xray-services-lambda.html&quot;&gt;https://docs.aws.amazon.com/xray/latest/devguide/xray-services-lambda.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Best practices for working with AWS Lambda functions, accessed on June 7, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Essential Guide to AWS Lambda Monitoring - Best Practices | SigNoz, accessed on June 7, 2025, &lt;a href=&quot;https://signoz.io/guides/aws-lambda-monitoring/&quot;&gt;https://signoz.io/guides/aws-lambda-monitoring/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Improve Your AWS Monitoring with CloudWatch Dashboards, accessed on June 7, 2025, &lt;a href=&quot;https://awsfundamentals.com/blog/improve-your-aws-monitoring-with-cloudwatch-dashboards&quot;&gt;https://awsfundamentals.com/blog/improve-your-aws-monitoring-with-cloudwatch-dashboards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Monitoring AWS Lambda errors using Amazon CloudWatch | AWS ..., accessed on June 7, 2025, &lt;a href=&quot;https://aws.amazon.com/blogs/mt/monitoring-aws-lambda-errors-using-amazon-cloudwatch/&quot;&gt;https://aws.amazon.com/blogs/mt/monitoring-aws-lambda-errors-using-amazon-cloudwatch/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sending Lambda function logs to CloudWatch Logs - AWS Documentation, accessed on June 7, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon CloudWatch Documentation, accessed on June 7, 2025, &lt;a href=&quot;https://www.amazonaws.cn/en/documentation-overview/Amazon-CloudWatch/&quot;&gt;https://www.amazonaws.cn/en/documentation-overview/Amazon-CloudWatch/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lambda Error Monitoring: Best Practices - AWS for Engineers, accessed on June 7, 2025, &lt;a href=&quot;https://awsforengineers.com/blog/lambda-error-monitoring-best-practices/&quot;&gt;https://awsforengineers.com/blog/lambda-error-monitoring-best-practices/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Log and monitor Java Lambda functions - AWS Documentation, accessed on June 7, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/java-logging.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/java-logging.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Monitoring Lambda applications - AWS Documentation, accessed on June 7, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/applications-console-monitoring.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/applications-console-monitoring.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Instrumenting Java code in AWS Lambda, accessed on June 7, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/java-tracing.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/java-tracing.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Complete Serverless Observability | Datadog, accessed on June 7, 2025, &lt;a href=&quot;https://www.datadoghq.com/product/serverless-monitoring/&quot;&gt;https://www.datadoghq.com/product/serverless-monitoring/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Serverless Monitoring for AWS Lambda - Datadog Docs, accessed on June 7, 2025, &lt;a href=&quot;https://docs.datadoghq.com/serverless/aws_lambda/&quot;&gt;https://docs.datadoghq.com/serverless/aws_lambda/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Serverless Warnings - Datadog Docs, accessed on June 7, 2025, &lt;a href=&quot;https://docs.datadoghq.com/serverless/guide/serverless_warnings/&quot;&gt;https://docs.datadoghq.com/serverless/guide/serverless_warnings/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Lambda - Datadog Docs, accessed on June 7, 2025, &lt;a href=&quot;https://docs.datadoghq.com/integrations/amazon_lambda/&quot;&gt;https://docs.datadoghq.com/integrations/amazon_lambda/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AWS Lambda</category><category>Serverless</category><category>Observability</category><category>Monitoring</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0100-aws-lambda-observability-guide/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Designing SLOs and Error Budgets: Your Blueprint for Sustainable Reliability</title><link>https://mkabumattar.com/blog/post/designing-slos-error-budgets-reliability-blueprint/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/designing-slos-error-budgets-reliability-blueprint/</guid><description>Learn how to design effective SLOs and error budgets to balance innovation with reliability. This comprehensive guide covers SLIs, monitoring, business goals, and best practices for sustained service health.</description><pubDate>Sat, 14 Mar 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In today&amp;#39;s fast-paced digital world, businesses are always trying to balance two big things: getting new features out fast and keeping their services super reliable. Every tech team deals with this, pushing for new ideas while making sure things stay stable. This is where Service Level Objectives (SLOs) and Error Budgets come into play. They give you a smart, data-backed way to decide how to balance speed and stability. They turn vague ideas of &amp;quot;good service&amp;quot; into clear, measurable goals that fit with what the business wants to achieve.&lt;/p&gt;
&lt;p&gt;This comprehensive guide will walk you through what SLOs and error budgets are, why they&amp;#39;re so important for businesses, how to set them up step-by-step, and how to use them to keep customers happy and new ideas coming. We&amp;#39;ll also cover common mistakes and answer your frequently asked questions, giving you a clear plan for building a more reliable future.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What Exactly Are SLOs, SLIs, and Error Budgets?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;If you want to build a truly reliable service, you need to get a handle on the basic pieces that define and measure how well it performs. These ideas Service Level Indicators (SLIs), Service Level Objectives (SLOs), and Error Budgets are the foundation of how we do reliability today.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Understanding Service Level Indicators (SLIs)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;A Service Level Indicator (SLI) is a specific, measurable way to tell how well your service is doing. Think of it as a precise number that shows exactly how a service is performing from a user&amp;#39;s point of view. Most SLIs work best as a ratio of &amp;quot;good events&amp;quot; to &amp;quot;total events,&amp;quot; which means they naturally go from 0% (nothing&amp;#39;s working) to 100% (everything&amp;#39;s perfect). This simple scale makes them super easy to use when you&amp;#39;re setting targets and budgets.&lt;/p&gt;
&lt;p&gt;Common SLIs include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Request Latency:&lt;/strong&gt; This measures how long it takes for a service to return a response to a request.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Rate:&lt;/strong&gt; This indicates the fraction of failed requests out of all requests received.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Availability/Uptime:&lt;/strong&gt; This represents the percentage of time a service is usable, often defined as the fraction of well-formed requests that succeed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Throughput:&lt;/strong&gt; Typically measured in requests per second or the volume of data processed, this indicates how many operations a system can handle.&lt;/li&gt;
&lt;li&gt;Other important SLIs can include durability for storage systems, freshness for data processing pipelines, and correctness.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ideally, an SLI measures exactly what your users care about most. For example, client-side latency is often more user-relevant, even if it&amp;#39;s harder to get than server-side latency. How clear, relevant, and measurable your SLI is forms the foundation for good SLOs and error budgets. If your SLIs aren&amp;#39;t well-defined, are too general, or don&amp;#39;t really focus on the user, your SLOs will end up vague or useless. This can mean your performance numbers don&amp;#39;t give you clear signals for what to do, or there&amp;#39;s just no real accountability. So, picking and defining your SLIs carefully is super important; they&amp;#39;re the basic data points everything else about reliability is built on. Even if an SLI is just a stand-in, a good one has to truly represent the user&amp;#39;s experience and how it affects them.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a simple Python function to calculate an SLI for success rate:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def calculate_success_rate_sli(good_events: int, total_events: int) -&amp;gt; float:
    &amp;quot;&amp;quot;&amp;quot;
    Calculates the Service Level Indicator (SLI) for success rate.

    Args:
        good_events: The number of successful events.
        total_events: The total number of events.

    Returns:
        The success rate as a percentage (0.0 to 100.0).
        Returns 0.0 if total_events is 0 to avoid division by zero.
    &amp;quot;&amp;quot;&amp;quot;
    if total_events == 0:
        return 0.0
    return (good_events / total_events) * 100.0

# Example usage:
successful_requests = 9980
total_requests = 10000
sli_value = calculate_success_rate_sli(successful_requests, total_requests)
print(f&amp;quot;Your service&amp;#39;s success rate SLI is: {sli_value:.2f}%&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Defining Service Level Objectives (SLOs)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;A Service Level Objective (SLO) is simply a target for how well your service should perform, measured by an SLI. It&amp;#39;s the agreed-upon goal for how well a service &lt;em&gt;should&lt;/em&gt; perform. For instance, an SLO might be &amp;quot;99.9% availability over a 30-day window&amp;quot; or &amp;quot;95% of API requests respond in under 300 milliseconds&amp;quot;. SLOs are internal goals that engineering teams use to check how healthy a service is over time. They&amp;#39;re really important for making data-driven decisions about reliability and deciding what engineering work to focus on. When you pick and share your SLOs, you set clear expectations for how your service will perform, and that can really cut down on baseless complaints from users.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Understanding Error Budgets&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The error budget is a core idea in Site Reliability Engineering (SRE). It&amp;#39;s the amount of &amp;quot;bad performance&amp;quot; or unreliability your service can handle within a certain timeframe while still hitting its overall SLO. You usually get this budget straight from your SLO: &lt;code&gt;Error Budget = 100% - SLO%&lt;/code&gt;. For example, if your goal is 99.9% availability, your error budget is 0.1%.&lt;/p&gt;
&lt;p&gt;This budget tells you the most downtime or malfunction you can have. If a service gets 3 million requests over a four-week period with a 99.9% success ratio SLO, its budget is 3,000 errors (0.1% of 3 million requests). Think of error budgets as a &amp;quot;buffer&amp;quot; or a &amp;quot;license to fail&amp;quot; in a controlled way. They let teams take smart risks, like deploying new code or trying out features, as long as they stay within their budget. This changes how we see reliability, from a fixed, abstract goal to a dynamic, measurable resource. Teams can actually &amp;quot;spend&amp;quot; their error budget on new features, which naturally come with some risk and potential unreliability, or they can &amp;quot;save&amp;quot; it by focusing on making things more reliable. This creates a real, data-driven trade-off, making reliability a strategic business decision, not just an engineering one. It gives you a &amp;quot;currency&amp;quot; to manage risk and how fast you innovate across the whole company.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;SLOs vs. SLAs: A Quick Distinction&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;People often use SLOs and Service Level Agreements (SLAs) interchangeably, but they&amp;#39;re actually different. An SLA is a contractually binding agreement with a customer that specifies the level of service they can expect. The big difference is that SLAs usually come with clear consequences, like money back or penalties, if the service provider doesn&amp;#39;t hit the agreed-upon levels. SLOs, on the other hand, are internal performance goals. They&amp;#39;re often stricter than the SLA and are used by engineering teams to make sure they&amp;#39;re on track to meet their external commitments. If you don&amp;#39;t meet an SLO, there&amp;#39;s usually no direct external penalty, but it definitely signals a potential risk to meeting your SLA later on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 1: Core Reliability Concepts: SLIs, SLOs, and Error Budgets&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Concept&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;What it is&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Relationship&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SLI (Service Level Indicator)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A specific, measurable metric of service performance.&lt;/td&gt;
&lt;td&gt;Quantifies service performance; forms the basis for SLOs.&lt;/td&gt;
&lt;td&gt;&amp;quot;99.9% of requests succeed&amp;quot; or &amp;quot;requests respond in &amp;lt; 300ms.&amp;quot;&lt;/td&gt;
&lt;td&gt;Measures performance against an SLO.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SLO (Service Level Objective)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A target value for an SLI over a defined period.&lt;/td&gt;
&lt;td&gt;Sets internal goals for reliability; aligns teams on performance expectations.&lt;/td&gt;
&lt;td&gt;&amp;quot;99.9% availability over 30 days.&amp;quot;&lt;/td&gt;
&lt;td&gt;A target for a specific SLI.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error Budget&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The allowable amount of unreliability within an SLO period.&lt;/td&gt;
&lt;td&gt;Balances innovation with reliability; quantifies acceptable failures.&lt;/td&gt;
&lt;td&gt;For a 99.9% SLO, 0.1% of events can be &amp;quot;bad.&amp;quot;&lt;/td&gt;
&lt;td&gt;Derived from the SLO (100% - SLO%).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SLA (Service Level Agreement)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A contractually binding agreement with external customers.&lt;/td&gt;
&lt;td&gt;Defines service commitments and outlines legal/financial consequences for non-compliance.&lt;/td&gt;
&lt;td&gt;&amp;quot;99.999% uptime for enterprise customers, with penalties for breaches.&amp;quot;&lt;/td&gt;
&lt;td&gt;An external commitment, often more lenient than internal SLOs.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Why Do SLOs and Error Budgets Matter for Your Business?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Reliability numbers aren&amp;#39;t just tech talk; they&amp;#39;re powerful tools that help your business succeed and make customers happier. Their impact goes way beyond just the engineering team, affecting big-picture decisions and helping create a healthier company culture.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Aligning Technical Performance with Business Goals&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;SLOs are much more than just technical numbers; they directly show how committed an organization is to service quality and, in the end, to making customers happy. They help turn big business ideas like &amp;quot;being a trusted partner&amp;quot; or &amp;quot;giving users a great experience&amp;quot; into clear, actionable standards for how your applications and infrastructure should perform. When you link SLOs directly to business goals, you make sure engineering teams are working on improving systems that really help the company succeed and make money. This proactive approach stops you from wasting resources on apps or features that aren&amp;#39;t really moving the business forward.&lt;/p&gt;
&lt;p&gt;This approach also makes companies clearly acknowledge, measure, and manage the &amp;quot;cost&amp;quot; of reliability. This cost isn&amp;#39;t just about money; it includes engineering time, the features you &lt;em&gt;don&amp;#39;t&lt;/em&gt; build, and the natural trade-offs in system design. By making this cost clear and real through the error budget, businesses can make smart, strategic investments in reliability that directly match their financial and market goals. It changes the conversation from an abstract &amp;quot;how reliable &lt;em&gt;can&lt;/em&gt; we be?&amp;quot; to a practical &amp;quot;how reliable &lt;em&gt;should&lt;/em&gt; we be, considering our business goals and what we have to work with?&amp;quot;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Balancing Innovation Velocity with Reliability&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This is probably the main reason error budgets exist and their biggest benefit. They give you a structured, data-driven way to manage service levels, helping you find a good balance between quickly releasing new features and keeping your system super stable. If there&amp;#39;s &amp;quot;room&amp;quot; in the error budget, teams can take smart risks with new deployments, experiments, or feature rollouts. On the flip side, if the budget is used up or almost gone, it&amp;#39;s a clear sign to stop new development and focus on reliability. Without an error budget, trying for an impossible 100% reliability means you can never update or improve your service, because changes are often what cause outages. This leads to stagnation, and eventually, customers will look for other options.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Fostering Shared Ownership and Alignment&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Error budgets help all the right teams development, operations, and product understand and share responsibility for reliability. Reliability isn&amp;#39;t just &amp;quot;Ops&amp;#39; problem&amp;quot; anymore. This shared language and data-driven way of making decisions really improve communication and get priorities and incentives aligned, encouraging teams to work together instead of pointing fingers. It helps avoid those chaotic &amp;quot;war rooms&amp;quot; and blame games that often happen when problems pop up without clear, agreed-upon reliability goals.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Enabling Data-Driven Decision-Making&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;SLOs and error budgets give you measurable data that directly guides and prioritizes engineering work. For instance, by figuring out how much a project might affect the error budget, companies can objectively decide which reliability improvement will help users the most. They&amp;#39;re powerful early warning signs of customer happiness, letting you proactively prevent churn and fix issues &lt;em&gt;before&lt;/em&gt; they make customers unhappy, instead of just reacting to things like Net Promoter Scores (NPS) or churn rates after the fact. When an error budget gets used up, it sends a clear, undeniable signal to switch focus from new features to fixing reliability right away.&lt;/p&gt;
&lt;p&gt;Adopting SLOs and error budgets means a big change in how you operate, moving from just fixing problems (firefighting) to actively managing risks. Instead of waiting for customer complaints or huge system crashes, teams can watch how fast their error budget is being used up as an early warning. This lets them step in &lt;em&gt;before&lt;/em&gt; the customer experience gets really bad, turning potential crises into manageable situations and creating a more stable, predictable environment for both users and the engineering teams supporting them.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How Do You Design Effective SLOs and Error Budgets? A Step-by-Step Guide&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Setting up reliability targets needs a structured approach where everyone works together. Here&amp;#39;s a practical way to design SLOs and error budgets that really help your business.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Step 1: Connect SLOs to Business Goals and Critical User Journeys (CUJs)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To make your SLOs really count, start by truly understanding how users interact with your service and what parts of that interaction are most important for their happiness and your business. Ultimately, SLOs should be all about making the customer experience better. This means figuring out which internal systems are critical the ones that make money or users interact with a lot and separating them from the supporting ones. You should prioritize these services based on how much they directly impact the business, how often they&amp;#39;re used, if they bring in revenue, and how they connect with other important services.&lt;/p&gt;
&lt;p&gt;Next, map out your Critical User Journeys (CUJs). These are the series of steps that make up a core part of a user&amp;#39;s experience and are essential to your service. For an e-commerce site, CUJs could be visiting the home page, searching for products, adding things to a cart, or finishing a purchase. Each step in a CUJ can have its own specific SLOs. Once you&amp;#39;ve identified critical systems, figure out the operational and financial costs if they don&amp;#39;t perform well. Work closely with your customer-facing teams to check this analysis and decide which reliability improvements to prioritize based on how they directly affect customers and revenue.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of how you might represent a Critical User Journey in code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Example of a Critical User Journey (CUJ) for an e-commerce platform
# Each step represents a key interaction a user has with the service.

e_commerce_cuj = {
    &amp;quot;name&amp;quot;: &amp;quot;Online Purchase Flow&amp;quot;,
    &amp;quot;steps&amp;quot;:
}

print(f&amp;quot;Critical User Journey: {e_commerce_cuj[&amp;#39;name&amp;#39;]}&amp;quot;)
for step in e_commerce_cuj[&amp;#39;steps&amp;#39;]:
    print(f&amp;quot;- Step {step[&amp;#39;id&amp;#39;]}: {step[&amp;#39;description&amp;#39;]} (Target Latency: {step[&amp;#39;expected_latency_ms&amp;#39;]}ms, Target Error Rate: {step[&amp;#39;expected_error_rate&amp;#39;] * 100}%)&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Step 2: Choose the Right Service Level Indicators (SLIs)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Pick measurable things that directly show what your users experience and how healthy your service is. The most common and effective choices are availability, latency, and error rate. A really good practice is to define SLIs as the ratio of &amp;quot;good events&amp;quot; to &amp;quot;total events&amp;quot;. This simple 0-100% scale fits perfectly with the idea of an error budget.&lt;/p&gt;
&lt;p&gt;Make sure your SLIs are clearly defined and you can measure them accurately from your current systems. Potential data sources include application server logs, load balancer monitoring, black-box monitoring, or client-side instrumentation. When you&amp;#39;re starting out, you don&amp;#39;t need to define every single possible SLI. Instead, pick one application, clearly define its users, and choose a few relevant, easy-to-measure things to begin with. You can always refine and expand later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 2: Example Service Level Indicators (SLIs) by Service Type&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Service Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Common SLIs&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Specific Example&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User-facing Web Application&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Availability, Latency, Error Rate&lt;/td&gt;
&lt;td&gt;99.9% of home page requests load in &amp;lt; 2 seconds.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Latency, Error Rate, Throughput&lt;/td&gt;
&lt;td&gt;99% of API requests return within 300 milliseconds.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Processing Pipeline&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Freshness, Throughput, Correctness&lt;/td&gt;
&lt;td&gt;Data ingestion rates of 5TB per day without degradation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage System&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Durability, Availability, Latency&lt;/td&gt;
&lt;td&gt;99.9999999% durability of data over a year.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;&lt;strong&gt;Step 3: Set Realistic SLO Thresholds&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s super important to get that aiming for 100% reliability is impossible and incredibly expensive. Systems are naturally complex, parts can and will break, and you often can&amp;#39;t control outside factors. Even more importantly, trying for absolute perfection means you can&amp;#39;t update or improve anything, because changes are often what cause outages. This makes your service stagnant and, strangely enough, leads to unhappy customers who will eventually look for more innovative options. Every extra &amp;quot;nine&amp;quot; in an SLO target (like going from 99.9% to 99.99%) means an exponential jump in the effort and cost to get there. If your SLOs are always being broken or always being met, they lose their meaning and don&amp;#39;t tell you anything useful about your application&amp;#39;s health.&lt;/p&gt;
&lt;p&gt;Designing good SLOs isn&amp;#39;t about hitting the highest reliability number possible. Instead, it&amp;#39;s about finding that &amp;quot;just right&amp;quot; spot the perfect balance that makes users happiest while still being affordable and technically possible for your engineering team. This zone isn&amp;#39;t fixed; it changes and needs constant tweaking based on real performance data, evolving user feedback, and shifting business priorities. It turns setting SLOs into an ongoing optimization problem, not just a one-time fixed target.&lt;/p&gt;
&lt;p&gt;Use your past performance data to set a baseline and create achievable goals. If you don&amp;#39;t have historical data, start with how things are performing now and plan to refine your targets as you gather more information. Don&amp;#39;t set SLOs higher than what&amp;#39;s truly necessary or meaningful for your users. For example, if users can&amp;#39;t tell the difference between a service responding in 300ms or 500ms, use the higher value as your latency threshold. The lower value costs more to meet, and users won&amp;#39;t even notice the difference.&lt;/p&gt;
&lt;p&gt;An SLO specifies a period of time over which you&amp;#39;re measuring the SLI. Rolling windows (like a 30-day rolling average) are often better because they show a continuous user experience, making sure a big outage isn&amp;#39;t just forgotten when a new month starts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 3: The &amp;quot;Nines&amp;quot; of Availability and Associated Downtime&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Availability Percentage&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Allowed Downtime (per year)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Allowed Downtime (per month)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;99% (Two Nines)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3 days, 15 hours, 36 minutes&lt;/td&gt;
&lt;td&gt;7 hours, 12 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;99.9% (Three Nines)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8 hours, 45 minutes, 36 seconds&lt;/td&gt;
&lt;td&gt;43 minutes, 12 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;99.99% (Four Nines)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;52 minutes, 36 seconds&lt;/td&gt;
&lt;td&gt;4 minutes, 19 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;99.999% (Five Nines)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5 minutes, 15 seconds&lt;/td&gt;
&lt;td&gt;26 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;99.9999% (Six Nines)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;31.5 seconds&lt;/td&gt;
&lt;td&gt;2.6 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;&lt;strong&gt;Step 4: Define Your Error Budget Policy&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Your error budget is just the opposite of your SLO: &lt;code&gt;100% - SLO%&lt;/code&gt;. This policy is super important; it tells you what happens when your error budget is being used up or is almost gone. Without a clear policy, the error budget is just a number.&lt;/p&gt;
&lt;p&gt;Common policy actions include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Alerting Thresholds:&lt;/strong&gt; Define specific thresholds (e.g., 50%, 75%, and 90% consumption) at which teams should be automatically notified.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code/Feature Freeze:&lt;/strong&gt; A common consequence is to halt new feature deployments until reliability improves and the service is back within its SLO.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reliability Sprints:&lt;/strong&gt; Redirect engineering resources to focus solely on fixing stability issues and reducing the error rate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mandatory Rollbacks:&lt;/strong&gt; If recent changes are suspected culprits for the budget consumption, the policy might mandate rolling back those changes to a stable state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The main goal of an error budget policy is to make your SLOs something you can actually act on. It turns the error budget from a passive number into an active way to control how you balance risk and innovation across your organization. This policy is much more than just a set of technical rules; it&amp;#39;s how an organization formally commits to a culture of reliability and shared responsibility. By clearly defining actions and consequences &lt;em&gt;before&lt;/em&gt; problems hit, it removes confusion, cuts down on blame, and empowers teams across different functions to make tough choices between building new features and keeping systems stable. This helps create a proactive, collaborative culture where reliability is a shared, real goal, not just an operational burden for one team.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a Python function that illustrates how an error budget policy might work:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def check_error_budget_status(slo_percentage: float, current_error_rate_percentage: float) -&amp;gt; str:
    &amp;quot;&amp;quot;&amp;quot;
    Checks the error budget status and suggests actions based on predefined policy thresholds.

    Args:
        slo_percentage: The Service Level Objective percentage (e.g., 99.9).
        current_error_rate_percentage: The current error rate observed as a percentage (e.g., 0.15 for 0.15%).

    Returns:
        A string indicating the status and suggested action.
    &amp;quot;&amp;quot;&amp;quot;
    error_budget_percentage = 100.0 - slo_percentage

    # Calculate how much of the error budget has been consumed
    # If current_error_rate_percentage is 0.15% and error_budget_percentage is 0.1%,
    # then consumption is 0.15 / 0.1 = 1.5 (or 150%)
    if error_budget_percentage == 0: # Avoid division by zero if SLO is 100%
        return &amp;quot;SLO is 100%, no error budget allowed. Any error means a breach.&amp;quot;

    consumption_ratio = current_error_rate_percentage / error_budget_percentage

    if consumption_ratio &amp;gt;= 1.0:
        return &amp;quot;Error budget exhausted! Immediately prioritize reliability work and consider a code freeze.&amp;quot;
    elif consumption_ratio &amp;gt;= 0.90: # 90% of budget consumed
        return &amp;quot;Error budget critically low (over 90% consumed). Alert all teams and prepare for reliability sprints.&amp;quot;
    elif consumption_ratio &amp;gt;= 0.75: # 75% of budget consumed
        return &amp;quot;Error budget nearing depletion (over 75% consumed). Review recent changes and plan for reliability work.&amp;quot;
    elif consumption_ratio &amp;gt;= 0.50: # 50% of budget consumed
        return &amp;quot;Error budget is at 50% consumption. Monitor closely and discuss potential reliability improvements.&amp;quot;
    else:
        return &amp;quot;Error budget is healthy. Continue with planned feature development.&amp;quot;

# Example usage:
slo_target = 99.9  # 0.1% error budget
current_errors_scenario_1 = 0.05 # 0.05% error rate
current_errors_scenario_2 = 0.08 # 0.08% error rate
current_errors_scenario_3 = 0.12 # 0.12% error rate (exceeds budget)

print(f&amp;quot;Scenario 1: {check_error_budget_status(slo_target, current_errors_scenario_1)}&amp;quot;)
print(f&amp;quot;Scenario 2: {check_error_budget_status(slo_target, current_errors_scenario_2)}&amp;quot;)
print(f&amp;quot;Scenario 3: {check_error_budget_status(slo_target, current_errors_scenario_3)}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Step 5: Gain Stakeholder Agreement and Document Everything&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For SLOs and error budgets to really work, everyone involved product managers, development teams, and SREs needs to agree on the proposed SLOs and the error budget policy. This makes sure everyone shares ownership and helps avoid &amp;quot;orphaned SLOs&amp;quot; or blame games when problems pop up.&lt;/p&gt;
&lt;p&gt;Write down your SLOs and the related error budget policy somewhere prominent and easy to find. This documentation should include things like who wrote, reviewed, and approved it, a description of the service, how specific SLIs are implemented, and why certain targets were chosen. Set up a regular schedule for reviewing and adjusting SLOs and policies (like monthly when you start, then quarterly or yearly as your culture matures). This makes sure they stay relevant as business needs, user expectations, and system capabilities change.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;The Indispensable Role of Monitoring and Observability&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To keep track of and understand your service&amp;#39;s reliability, strong monitoring and observability practices are absolutely essential. They give you the data and insights you need to make sure SLOs are met and error budgets are managed well.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Monitoring: The Foundation of Data Collection&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Monitoring means collecting numbers from your production systems to understand how they&amp;#39;re behaving. It involves gathering raw data like CPU usage, memory use, and how many requests are coming in. Its main jobs are to help you debug and to send alerts when you need to step in, making sure teams know about issues as they happen. Monitoring gives you the raw data that directly feeds into SLI calculations and forms the basis for tracking your error budget.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Observability: Deeper Insights into System State&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Observability goes beyond just basic monitoring. It&amp;#39;s about how well you can understand what&amp;#39;s going on inside a system by looking at what it puts out. The goal is to figure out the hidden internal causes from external signs using different kinds of data, often called &amp;quot;telemetry data&amp;quot;.&lt;/p&gt;
&lt;p&gt;Key Telemetry Data for Observability:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Metrics:&lt;/strong&gt; These are quantitative measurements (raw, derived, or aggregated) that show system health and performance over specific time intervals. Metrics are the direct input for SLIs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logs:&lt;/strong&gt; Detailed, timestamped textual records of events within a system. Logs are crucial for understanding chronological context and diagnosing the precise sequence of events that led to an issue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traces:&lt;/strong&gt; These provide a comprehensive view of a data request&amp;#39;s lifecycle from its initiation to completion. Tracing, especially distributed tracing, is invaluable in complex microservices architectures where a single request might traverse multiple services, helping to pinpoint bottlenecks and dependencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Better observability directly means you can diagnose problems more effectively and fix them faster. Observability isn&amp;#39;t just a nice-to-have; it&amp;#39;s the crucial technical ability that turns SLOs from theoretical targets into practical, real-time control mechanisms. Without deep observability (metrics, logs, traces), teams might know they&amp;#39;ve broken an SLO, but they won&amp;#39;t have the crucial context to quickly understand &lt;em&gt;why&lt;/em&gt; it happened or &lt;em&gt;how&lt;/em&gt; to fix it efficiently. This means observability is the essential bridge between &lt;em&gt;knowing&lt;/em&gt; there&amp;#39;s a problem and &lt;em&gt;solving&lt;/em&gt; it efficiently, which helps preserve your error budget and keep things reliable.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Monitoring and Observability Feed SLOs and Error Budgets&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Monitoring systems gather the raw data you need to calculate SLIs (like counting successful requests or measuring latency). Observability tools then collect, connect, and analyze all this rich telemetry data, giving you deep insight into how your system behaves. This lets Site Reliability Engineers (SREs) track specific observability metrics, often called the &amp;quot;four golden signals&amp;quot; (latency, traffic, errors, and saturation), to have data-driven conversations about how healthy your product is. These insights are vital for measuring how well you&amp;#39;re meeting your SLOs and tracking error budget consumption in real-time, giving you a clear picture of your service&amp;#39;s reliability status.&lt;/p&gt;
&lt;p&gt;The connection between monitoring, observability, and SLOs creates a continuous, self-improving feedback loop. Data gathered through monitoring and made richer by observability shows you the real-time status of your SLIs against your SLOs. Breaches or high error budget burn rates kick off actions, guided by your established error budget policy. The results of these actions then feed back into the monitoring system, letting you continuously refine your SLO targets and make further system improvements. This ongoing process is fundamental for achieving lasting reliability and adapting to changing user needs, system complexities, and business demands.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Proactive Issue Detection and Root Cause Analysis&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;With strong observability tools in place, SRE teams can spot and fix system issues &lt;em&gt;before&lt;/em&gt; they really affect users. This changes your approach from just reacting to problems (firefighting) to actively preventing them. Observability solutions give engineers the power to quickly figure out the root cause of problems, often without needing a lot of manual testing or extra coding. Advanced AI-based observability functions can constantly watch incoming data, automatically find activities that go over set limits, and even perform a series of corrective actions, like running remediation scripts.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Managing Your Error Budget: Practical Strategies for Sustained Reliability&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Once you&amp;#39;ve defined your SLOs and error budgets, the next really important step is actively managing them. This means understanding how your budget is being used up and putting strategies in place to make sure you&amp;#39;re spending it wisely to keep things reliable.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Understanding and Tracking Error Budget Burn Rate&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s not enough to just define an error budget; organizations need to actively track how fast it&amp;#39;s being used up that&amp;#39;s called the &amp;quot;burn rate&amp;quot;. A burn rate above 1.0 means your budget is running out faster than planned, so your service is seeing more errors than you expected for that period. This burn rate acts as a crucial early warning, telling you when a service&amp;#39;s customer experience is slipping or is about to get much worse. Tracking &lt;em&gt;how fast&lt;/em&gt; your error budget is being used up is often more powerful and actionable than just knowing how much is left. A high burn rate, even if you haven&amp;#39;t used up the whole budget, signals a problem that&amp;#39;s getting worse quickly and could soon affect customer satisfaction and, by extension, important business numbers like churn and revenue. It gives you a crucial early warning, letting you step in &lt;em&gt;before&lt;/em&gt; you fully breach an SLO, essentially turning technical performance numbers into direct, early signals of your overall business health.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Implementing Effective Alerting Strategies&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Set up automated alerts that go off when your error budget is almost gone. It&amp;#39;s common practice to tell teams when they&amp;#39;ve used up certain amounts, like 50%, 75%, and 90% of the budget. You should set up alerts carefully to focus on actual user impact and avoid false alarms, which can lead to &amp;quot;alert fatigue&amp;quot; and make teams ignore real problems. Crucially, these alerts should be linked to clear steps for fixing things or automated runbooks. This makes incident response smoother, ensuring teams know exactly what to do when an alert goes off.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Decision-Making Frameworks for Prioritizing Reliability Work&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;When your error budget is almost gone or completely used up, your pre-defined error budget policy should automatically kick in. This usually means you&amp;#39;ll prioritize fixing critical reliability issues over rolling out new features. The budget acts as a clear signal to change your focus.&lt;/p&gt;
&lt;p&gt;Actions might include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Code/Feature Freezes:&lt;/strong&gt; Halting new feature deployments until reliability improves and the service is back within its SLO.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reliability Sprints:&lt;/strong&gt; Redirecting dedicated engineering resources to focus solely on stability work and reducing the error rate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System Rollbacks:&lt;/strong&gt; Reverting to a previous stable version if recent changes are identified as the cause of the budget consumption.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The error budget helps you measure how big an incident was (for example, &amp;quot;this outage used up 30% of my quarterly error budget&amp;quot;), which is super valuable for finding critical incidents to investigate deeply and for deciding which reliability projects to tackle next. The error budget turns that often-abstract tension between &amp;quot;moving fast and breaking things&amp;quot; and &amp;quot;keeping things stable&amp;quot; into a measurable, negotiable resource. It gives product, development, and SRE teams a common, data-driven language to have objective talks about risk, investment, and priorities. Instead of emotional debates, teams can look at the remaining budget to decide whether to push a new feature or stop releases to fix reliability problems. This helps create a more mature, collaborative, and accountable decision-making process across the whole organization.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Considerations for Planned Maintenance Windows&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Scheduled maintenance, even though it&amp;#39;s necessary, can eat into your error budget. It&amp;#39;s important to plan for this. You should strategically plan maintenance windows to happen when user activity is low, to minimize negative effects on users and save your budget. Past traffic data can help you schedule this. You should communicate maintenance windows effectively and transparently to users and stakeholders. This manages expectations and keeps people from getting too upset, even if there&amp;#39;s a temporary service disruption. For critical services, think about explicitly including planned maintenance downtime in your error budget during business hours as a strategic business decision, making sure it&amp;#39;s accounted for and managed.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Common Pitfalls and How to Avoid Them&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Putting SLOs and error budgets in place can really boost reliability, but companies often run into common traps that can make them less effective. Understanding these challenges and using best practices is key to success.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Common Pitfalls&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Defining Too Many SLOs:&lt;/strong&gt; Having too many SLOs for one service can overwhelm teams and pull their focus away from what really matters to users. Engineers often find it hard to decide which SLOs are &amp;quot;must-dos&amp;quot; versus &amp;quot;nice-to-dos,&amp;quot; which wastes their valuable time. Google suggests sticking to a manageable 3-5 critical SLOs per user journey.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setting Unrealistic Reliability Targets:&lt;/strong&gt; Trying for extremely high SLOs, like 99.999% or even 100% reliability, is often impractical and incredibly expensive. Such high targets leave almost no error budget for crucial activities like adding features, deploying new hardware, or scaling to meet customer demand, which can make your service stagnate. If your SLOs are always being broken or always being met, they lose their meaning and don&amp;#39;t tell you anything useful about your application&amp;#39;s health.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lack of Ownership or Accountability:&lt;/strong&gt; When upper management creates SLOs without enough buy-in from the development, operations, and SRE teams, it can lead to &amp;quot;orphaned SLOs&amp;quot; and chaotic &amp;quot;war rooms&amp;quot; full of finger-pointing and blame when things go wrong. A broken SLO without a clear owner will likely take longer to fix and is more likely to happen again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using SLOs Reactively vs. Proactively:&lt;/strong&gt; Many companies adopt SLOs just because it&amp;#39;s a trend, without fully understanding the business goal behind it. In those cases, IT teams might only pay attention to SLOs when they&amp;#39;re violated, leading to a reactive scramble to fix things. This reactive approach really lessens the value SLOs bring to keeping applications healthy, reliable, and resilient, and it doesn&amp;#39;t stop similar problems from happening again, wasting valuable developer time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not Performing Service Decomposition:&lt;/strong&gt; In really complex systems, if you don&amp;#39;t break down the technical architecture into simpler, manageable parts before defining SLOs, you can end up with unrealistic goals and it becomes super hard to find the root cause when an SLO is breached. For example, a &amp;quot;checkout success rate&amp;quot; SLO might be breached, but without decomposition, the team won&amp;#39;t know if the problem is with the frontend, the payment gateway, or the inventory database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ignoring Error Budgets or Lacking a Clear Policy:&lt;/strong&gt; Treating error budgets as an afterthought, or not having a clear policy for what to do when the budget is used up, leads to big problems in reliability efforts. Without a clear policy, teams don&amp;#39;t have clear guidance on what to do when the service runs out of its allowed unreliability.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;Best Practices to Avoid Pitfalls&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keep it Short and Simple (KISS Principle):&lt;/strong&gt; Focus on a few really relevant, measurable, and critical metrics (like availability, latency, and error rate) that directly affect the user experience. Don&amp;#39;t make things more complicated than they need to be.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start Small and Iterate:&lt;/strong&gt; Begin by defining SLOs for just one, high-impact application. Figure out its users and their main interactions, map out its high-level architecture and dependencies, and then slowly expand your SLO coverage. Your first SLI/SLO doesn&amp;#39;t have to be perfect; the goal is to get something working and learn from it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Align with Business Objectives Regularly:&lt;/strong&gt; Set up a regular review schedule to continuously check and adjust your SLOs (like monthly, quarterly, or semi-annually). During reviews, think about whether the SLO still matches user needs, if it&amp;#39;s realistic based on past data, and if any changes in performance or traffic mean you need to update it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build on Metrics History:&lt;/strong&gt; Use historical data to see how your system has performed over time and spot trends like seasonal traffic spikes, increasing user load, or performance getting worse. Setting targets based on history stops you from overcommitting to goals that could strain resources or frustrate your teams.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build SLO Observability:&lt;/strong&gt; Gather rich telemetry data (Metrics, Events, Logs, and Traces) to figure out user-centric SLOs and enable proactive anomaly detection. Set up dashboards and reports to track performance against SLOs, customized for your audience, scope, and requirements.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do SLOs differ from KPIs?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Key Performance Indicators (KPIs) are bigger business numbers that measure the overall success of a company or project, like customer satisfaction scores, revenue growth, or market share. SLOs, on the other hand, are specific, technical targets for how your service performs that directly contribute to those bigger KPIs. While a KPI might be &amp;quot;increase customer retention by 5%,&amp;quot; an SLO would be &amp;quot;99.9% availability of the login service,&amp;quot; which directly helps with customer retention. SLOs are actionable and directly guide engineering decisions, while KPIs are often lagging indicators that show the &lt;em&gt;result&lt;/em&gt; of many underlying factors.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What happens if an error budget goes negative?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;A negative error budget means your service has used up more than its allowed error budget and isn&amp;#39;t meeting its Service Level Objective. This means the service hasn&amp;#39;t been as reliable as you agreed it should be. When this happens, it&amp;#39;s a clear sign to immediately prioritize reliability work. Common actions include pausing new feature deployments (a &amp;quot;code freeze&amp;quot;), redirecting engineering resources to fix the underlying issues, or even performing system rollbacks if recent changes are suspected culprits. A negative error budget means you need to do a postmortem analysis to understand &lt;em&gt;why&lt;/em&gt; it happened and take corrective actions to get things stable again and rebuild your budget.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can SLOs be too strict or too loose?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, SLOs can definitely be too strict or too loose, and both can cause problems. If SLOs are too strict (like aiming for 100% reliability), they become impossible to meet, lead to constant violations, burn out engineering teams, and stop new ideas by leaving no room for change or trying new things. On the other hand, if SLOs are too loose (like 89% availability for a critical customer-facing service), they become meaningless because they&amp;#39;re either always met despite a bad user experience, or they allow for unacceptable downtime that hurts customers and business goals. The goal is to find that &amp;quot;just right&amp;quot; spot where SLOs are challenging but achievable, match user expectations, and give you meaningful signals for what to do.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Designing and putting SLOs and error budgets into practice isn&amp;#39;t just a technical task; it&amp;#39;s a strategic must-have for any organization that wants to deliver reliable services and keep innovating sustainably. These powerful tools give you a measurable language for reliability, turning abstract goals into targets you can act on. By carefully defining SLIs, setting realistic SLOs, and creating clear error budget policies, businesses can align technical efforts with their big-picture business goals, give teams shared ownership, and move from just reacting to problems to actively managing risks.&lt;/p&gt;
&lt;p&gt;The path to mature reliability practices is ongoing; it needs consistent monitoring, deep observability, and a commitment to continuous improvement. Embracing SLOs and error budgets lets organizations make smart, data-driven decisions about where to put their engineering time and resources, making sure customer satisfaction stays top of mind while still letting them deliver new features quickly. Ultimately, this blueprint for reliability sets the stage for a more stable, predictable, and successful digital future.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Defining SLO: Service Level Objective Meaning - Google SRE, accessed on June 6, 2025, &lt;a href=&quot;https://sre.google/sre-book/service-level-objectives/&quot;&gt;https://sre.google/sre-book/service-level-objectives/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Implementing SLOs - Google SRE, accessed on June 6, 2025, &lt;a href=&quot;https://sre.google/workbook/implementing-slos/&quot;&gt;https://sre.google/workbook/implementing-slos/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Understanding Error Budgets: Balancing Innovation and Reliability - PFLB, accessed on June 6, 2025, &lt;a href=&quot;https://pflb.us/blog/understanding-error-budgets-balancing-innovation-reliability/&quot;&gt;https://pflb.us/blog/understanding-error-budgets-balancing-innovation-reliability/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SLI, SLO, SLA, Error Budget - A Primer, accessed on June 6, 2025, &lt;a href=&quot;https://bala-krishnan.com/posts/19-sli-slo-sla/&quot;&gt;https://bala-krishnan.com/posts/19-sli-slo-sla/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SLOs, SLIs, and SLAs: Meanings &amp;amp; Differences | New Relic, accessed on June 6, 2025, &lt;a href=&quot;https://newrelic.com/blog/best-practices/what-are-slos-slis-slas&quot;&gt;https://newrelic.com/blog/best-practices/what-are-slos-slis-slas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Understanding SLAs, SLOs, SLIs and Error Budgets - Stytch, accessed on June 6, 2025, &lt;a href=&quot;https://stytch.com/blog/understanding-slas-error-budgets&quot;&gt;https://stytch.com/blog/understanding-slas-error-budgets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Comprehensive Guide on SLIs, SLOs, and Error Budgets, accessed on June 6, 2025, &lt;a href=&quot;https://www.blameless.com/the-comprehensive-guide-on-slis-slos-and-error-budgets&quot;&gt;https://www.blameless.com/the-comprehensive-guide-on-slis-slos-and-error-budgets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Understanding Error Budgets And Their Importance In SRE - Netdata, accessed on June 6, 2025, &lt;a href=&quot;https://www.netdata.cloud/academy/error-budget/&quot;&gt;https://www.netdata.cloud/academy/error-budget/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Common SLO pitfalls and how to avoid them - Dynatrace, accessed on June 6, 2025, &lt;a href=&quot;https://www.dynatrace.com/news/blog/common-slo-pitfalls-and-how-to-avoid-them/&quot;&gt;https://www.dynatrace.com/news/blog/common-slo-pitfalls-and-how-to-avoid-them/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Reliability, monitoring, observability | Nobl9 Documentation, accessed on June 6, 2025, &lt;a href=&quot;https://docs.nobl9.com/slocademy/before-we-begin/reliability-observability-monitoring&quot;&gt;https://docs.nobl9.com/slocademy/before-we-begin/reliability-observability-monitoring&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>SRE</category><category>SLO</category><category>Error Budgets</category><category>Reliability</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0099-designing-slos-error-budgets-reliability-blueprint/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Edge Computing: AWS Lambda@Edge vs. Cloudflare Workers – A Practical Guide</title><link>https://mkabumattar.com/blog/post/edge-computing-aws-lambda-at-edge-vs-cloudflare-workers-practical-guide/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/edge-computing-aws-lambda-at-edge-vs-cloudflare-workers-practical-guide/</guid><description>Dive into edge computing with our practical guide comparing AWS Lambda@Edge and Cloudflare Workers. Discover their strengths, weaknesses, and ideal use cases for serverless, low-latency applications. Learn how these CDN-integrated platforms optimize performance for web apps and IoT, helping you choose the right solution.</description><pubDate>Sat, 07 Mar 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The digital world keeps changing, and so do the demands on our apps and services. We all expect instant responses, smooth experiences, and things to just work, no matter where we are. This constant push for speed and efficiency has really put &lt;strong&gt;edge computing&lt;/strong&gt; in the spotlight. It&amp;#39;s a game-changer for how we deliver digital content and services. Basically, it moves processing closer to you, the user, and that totally changes how applications perform. In this post, we&amp;#39;re going to dig into this important idea and then look at two top platforms that make it happen: &lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt; and &lt;strong&gt;Cloudflare Workers&lt;/strong&gt;. We&amp;#39;ll give you a practical comparison to help you figure out which one might be right for your needs.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What&amp;#39;s the Buzz About Edge Computing?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;So, what&amp;#39;s all the talk about &lt;strong&gt;edge computing&lt;/strong&gt;? It&amp;#39;s a pretty big change in how we handle and process data. Think of it this way: instead of sending all your data to a faraway, central cloud server, edge computing brings the computing power much closer to where the data is actually created or used. Picture a tiny computer sitting right next to your smart device or right where you are, processing information right there instead of sending it on a long trip to a huge data center. This idea of keeping things close is why edge computing is becoming so important. That direct closeness opens up all sorts of new possibilities for apps and really makes user experiences better across different industries. It&amp;#39;s like we&amp;#39;re moving from just using big central clouds to a mix of distributed systems. We&amp;#39;re choosing the best spot for computing based on things like how fast we need a response, how much data we&amp;#39;re sending, and security needs, not just raw power. This really shows how important network setup is in today&amp;#39;s app design.&lt;/p&gt;
&lt;p&gt;Why does this matter for today&amp;#39;s applications? Well, the benefits are huge and affect a lot of areas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reduced Latency and Faster Responses:&lt;/strong&gt; First off, &lt;strong&gt;low-latency&lt;/strong&gt; and faster responses. This is probably the biggest win. When you process data closer to where it starts, &lt;strong&gt;edge computing&lt;/strong&gt; drastically cuts down the time it takes for data to go back and forth. This means your apps respond much, much faster. For apps where every second counts like smart security systems, self-driving cars, or factory automation even a two-second delay could be a disaster. That&amp;#39;s why edge computing is so fundamental for critical systems, especially with all the new &lt;strong&gt;IoT&lt;/strong&gt; devices popping up. The need for instant decisions and quick responses in these vital apps is what&amp;#39;s really driving people to use strong edge solutions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lower Bandwidth Usage and Costs:&lt;/strong&gt; You&amp;#39;ll also see lower bandwidth use and costs. When data gets processed right there at the edge, you don&amp;#39;t have to send as much of it all the way to a central cloud server. This cuts down on data transfer, which means less network bandwidth used, and that can save you a lot of money, especially if your apps handle tons of data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced Reliability and Security:&lt;/strong&gt; Plus, you get better reliability and security. Edge setups let important apps keep working even if your main internet connection acts up or goes offline, because the processing happens right there. And security gets a boost too: keeping sensitive data closer to where it started means there&amp;#39;s less chance of someone intercepting it while it travels long distances over networks that might not be as secure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time Decision-Making:&lt;/strong&gt; And for &lt;strong&gt;IoT&lt;/strong&gt;, it&amp;#39;s all about real-time decision-making. With billions of devices creating massive amounts of data, &lt;strong&gt;edge computing&lt;/strong&gt; helps you analyze it instantly and respond quickly. This is super important for real-time operations and really boosts how well your whole system performs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;AWS Lambda@Edge: Powering the Edge with AWS&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Now, let&amp;#39;s talk about &lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt;. It&amp;#39;s a really powerful add-on to Amazon CloudFront, which is AWS&amp;#39;s worldwide &lt;strong&gt;CDN&lt;/strong&gt; (Content Delivery Network). It lets you run &lt;strong&gt;serverless&lt;/strong&gt; code, or what we call functions, right at AWS&amp;#39;s global edge locations. These spots are placed strategically closer to users all over the world. This means you don&amp;#39;t have to set up or look after servers in a bunch of different places, which makes managing your infrastructure a lot simpler. You only pay for the time your code actually runs; there&amp;#39;s no charge when it&amp;#39;s just sitting there.&lt;/p&gt;
&lt;p&gt;How does Lambda@Edge work with CloudFront? Your functions run when certain things happen during the CloudFront &lt;strong&gt;CDN&lt;/strong&gt;&amp;#39;s process. These are called events, and they give you flexible spots to run your code within the request and response flow&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Viewer Request:&lt;/strong&gt; A &lt;strong&gt;Viewer Request&lt;/strong&gt; event fires before CloudFront even checks its cache or sends the request to your main server. It&amp;#39;s perfect for things like A/B testing, custom logins, or changing HTTP headers. For example, you could use a Viewer Request function to add a custom header to every incoming request. Here&amp;#39;s a simple Node.js example:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#39;use strict&amp;#39;;

// This function runs on a Viewer Request event
exports.handler = (event, context, callback) =&amp;gt; {
  const request = event.Records.cf.request;
  const headers = request.headers;

  // Add a custom header to the request before it goes to CloudFront&amp;#39;s cache or origin
  headers[&amp;#39;x-custom-header&amp;#39;] = [
    {key: &amp;#39;X-Custom-Header&amp;#39;, value: &amp;#39;Hello from Lambda@Edge!&amp;#39;},
  ];

  // Pass the modified request back to CloudFront
  callback(null, request);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Origin Request:&lt;/strong&gt; If CloudFront doesn&amp;#39;t have what it needs in its cache, an &lt;strong&gt;Origin Request&lt;/strong&gt; event kicks in before the request hits your main backend server. This is handy for smart routing based on what&amp;#39;s in the request or for signing requests to other servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Origin Response:&lt;/strong&gt; An &lt;strong&gt;Origin Response&lt;/strong&gt; event happens after your main server sends a response back to CloudFront, but before CloudFront stores it in its cache. You can use this to change response headers or transform content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Viewer Response:&lt;/strong&gt; Finally, the &lt;strong&gt;Viewer Response&lt;/strong&gt; event processes responses right before CloudFront sends them to the person using your app.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Developers write Lambda@Edge functions in the AWS Lambda console, usually in the us-east-1 region. CloudFront then automatically copies these functions all over its global network of edge locations.&lt;/p&gt;
&lt;p&gt;Lambda@Edge can do a lot of things and has many uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Content Customization and Personalization:&lt;/strong&gt; You can customize and personalize content. It lets you deliver different content or experiences based on things like where a user is, what device they&amp;#39;re using, or other request details. For example, you can resize images instantly to fit mobile phones or desktop computers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Enhancements:&lt;/strong&gt; It also boosts security. Functions can add HTTP security headers, make sure only authorized users get in, or block unwanted bots right at the edge. This helps protect your backend servers and makes them less vulnerable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO Optimization:&lt;/strong&gt; You can even optimize for SEO. It can serve pre-rendered HTML pages to search engine bots, which helps with indexing, while regular users still get dynamic content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Routing and Load Balancing:&lt;/strong&gt; It helps with dynamic routing and load balancing. You can smartly send requests to different servers or data centers based on various factors, which makes things faster and spreads the workload out well.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time Data Processing (IoT &amp;amp; Analytics):&lt;/strong&gt; For &lt;strong&gt;IoT&lt;/strong&gt; and analytics, it&amp;#39;s great for real-time data processing. Lambda@Edge can process data from &lt;strong&gt;IoT&lt;/strong&gt; devices closer to where it&amp;#39;s generated, helping apps in manufacturing, agriculture, and logistics make faster decisions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Gateway Integration:&lt;/strong&gt; It also integrates with API Gateway. It acts as a &lt;strong&gt;serverless&lt;/strong&gt; backend for web and mobile apps, handling the app&amp;#39;s logic and working smoothly with other AWS services like S3 or DynamoDB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But even with all its strengths, Lambda@Edge does have a few limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cold Starts:&lt;/strong&gt; You might run into &amp;quot;cold starts.&amp;quot; While it&amp;#39;s quicker than regular AWS Lambda, Lambda@Edge can still have a delay when a function runs for the very first time or after it&amp;#39;s been sitting idle for a while. This can affect apps that really need consistent, &lt;strong&gt;low-latency&lt;/strong&gt; responses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language Support:&lt;/strong&gt; It mainly supports Node.js and Python. That&amp;#39;s a bit less variety compared to some other &lt;strong&gt;serverless&lt;/strong&gt; options out there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource Limits:&lt;/strong&gt; There are some resource limits. You can set memory up to 10GB, but functions are billed in 50ms chunks. Also, request bodies get cut off for processing for example, at 40KB for viewer request events and 1MB for origin request events.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deployment Complexity:&lt;/strong&gt; Deploying can be a bit complex. Every time you update a Lambda@Edge function, you need a new CloudFront deployment, and that can take a while to spread across the globe.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logging:&lt;/strong&gt; And for logging, your logs go to CloudWatch in the specific region where the function ran. So, you might need a way to gather all those logs in one place for easier monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One big thing about Lambda@Edge is how well it works with the whole AWS world. This wide-ranging connection means you can build complex systems with many different services, letting your functions talk smoothly with things like S3, DynamoDB, and &lt;strong&gt;IoT&lt;/strong&gt; Core. If you&amp;#39;re already using a lot of AWS, this is a huge plus. It gives you a familiar place to work and easy connections to tons of AWS services. But this strength also means you&amp;#39;re pretty tied to one vendor, and its global distribution might not feel as &amp;quot;native&amp;quot; as platforms designed for the edge from day one. Deciding between Lambda@Edge and other options often depends on your current cloud plan. If AWS is your main cloud provider, Lambda@Edge just feels like a natural fit.&lt;/p&gt;
&lt;p&gt;When it comes to performance, Lambda@Edge aims for &lt;strong&gt;low-latency&lt;/strong&gt; but those cold starts and the fact that it&amp;#39;s billed in 50ms chunks tell us it&amp;#39;s not always instant. Tests show that for 95% of requests, Lambda@Edge can be slower than some other options. So, while it&amp;#39;s a big step up from regular Lambda functions for edge tasks, its performance might not be as consistently perfect as a platform built specifically to get rid of cold starts. This is especially true for super sensitive, high-traffic jobs where every millisecond really matters. The way Lambda@Edge runs, using containers even at the edge, can still cause those cold starts, and that affects how consistently you get &lt;strong&gt;low-latency&lt;/strong&gt; performance. It&amp;#39;s a key difference in how it&amp;#39;s built compared to some competitors.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Cloudflare Workers: A Global Network at Your Fingertips&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Next up, &lt;strong&gt;Cloudflare Workers&lt;/strong&gt;. This is a &lt;strong&gt;serverless&lt;/strong&gt; platform that lets developers run their code right on Cloudflare&amp;#39;s huge global network, which has more than 330 data centers all over the world. This means you can build and deploy &lt;strong&gt;serverless&lt;/strong&gt; functions and apps without having to worry about setting up or looking after any servers at all.&lt;/p&gt;
&lt;p&gt;What makes Cloudflare Workers stand out? It&amp;#39;s their unique design and massive global reach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;V8 Isolates:&lt;/strong&gt; They use something called V8 Isolates. Unlike typical &lt;strong&gt;serverless&lt;/strong&gt; platforms that might use full Node.js processes or containers, Cloudflare Workers run code inside Chrome V8 isolates. These isolates start up way faster, usually in under 5 milliseconds, and they don&amp;#39;t use much memory. This design choice is why they can offer &amp;quot;near-zero&amp;quot; or &amp;quot;0ms cold start&amp;quot; performance, which is a huge competitive edge. This V8 isolate setup directly gives you those super-fast cold start times, and that means a much better, more consistent experience for interactive web apps and APIs. It&amp;#39;s their answer to a common problem in the &lt;strong&gt;serverless&lt;/strong&gt; world. A basic Cloudflare Worker is quite simple. It listens for fetch events (HTTP requests) and responds. Here&amp;#39;s a quick example:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// This is a simple Cloudflare Worker that responds to all requests
addEventListener(&amp;#39;fetch&amp;#39;, (event) =&amp;gt; {
  // We tell the event to wait for the response from our handleRequest function
  event.respondWith(handleRequest(event.request));
});

/**
 * Handles incoming requests and returns a response.
 * @param {Request} request The incoming HTTP request.
 * @returns {Response} The HTTP response.
 */
async function handleRequest(request) {
  // Return a simple text response
  return new Response(&amp;#39;Hello from Cloudflare Workers!&amp;#39;, {
    headers: {&amp;#39;content-type&amp;#39;: &amp;#39;text/plain&amp;#39;},
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Massive Global Network (CDN Integration):&lt;/strong&gt; They have a massive global network, with &lt;strong&gt;CDN&lt;/strong&gt; integration built right in. Cloudflare&amp;#39;s network has hundreds of data centers worldwide. This means your code runs super close to your users, no matter where they are. This global setup naturally keeps &lt;strong&gt;latency&lt;/strong&gt; to a minimum.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anycast Technology:&lt;/strong&gt; They use Anycast Technology. Incoming requests automatically go to the closest data center using Anycast, which really cuts down on &lt;strong&gt;latency&lt;/strong&gt;. It&amp;#39;s a big difference compared to traditional &lt;strong&gt;serverless&lt;/strong&gt; platforms that need you to set up new endpoints in every location to get that low global &lt;strong&gt;latency&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cloudflare Workers can do a lot of different things and have many uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ultra-Low Latency Content Delivery:&lt;/strong&gt; They offer ultra-low &lt;strong&gt;latency&lt;/strong&gt; content delivery. They make web and API performance faster worldwide by running code right at the network&amp;#39;s edge. This is perfect for dynamic content, changing APIs on the fly, and A/B testing, giving users a consistently fast experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time Data Manipulation:&lt;/strong&gt; You can do real-time data manipulation. Workers can handle complex changes, user authentication, and custom caching without adding any extra &lt;strong&gt;latency&lt;/strong&gt; to your main backend systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Front-end and Full-stack Applications:&lt;/strong&gt; They&amp;#39;re great for front-end and full-stack applications. You can host static files right on Cloudflare&amp;#39;s &lt;strong&gt;CDN&lt;/strong&gt; and cache, or build full-stack apps with built-in support for popular frameworks like React, Vue, Next.js, and Astro.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Acceleration:&lt;/strong&gt; They help with API acceleration. Workers make REST and GraphQL APIs faster by handling queries and gathering data closer to the user. They do this using tricks like grouping requests and smart caching at the field level, which means super-fast API responses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IoT Data Processing:&lt;/strong&gt; For &lt;strong&gt;IoT&lt;/strong&gt; data processing, they work with outside services to process &lt;strong&gt;IoT&lt;/strong&gt; data, letting you handle events and make changes in real-time right at the edge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security and Bot Mitigation:&lt;/strong&gt; They also boost security and help with bot mitigation. Cloudflare Workers get the benefit of Cloudflare&amp;#39;s built-in DDoS protection, WAF (Web Application Firewall), and rate limiting. These often come with automatic updates and pre-set rules, making your app more secure at the edge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serverless AI Inference:&lt;/strong&gt; You can even do &lt;strong&gt;serverless&lt;/strong&gt; AI inference. They can run machine learning models and create images right at the edge using Workers AI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Background Jobs:&lt;/strong&gt; And for background jobs, Workers can schedule cron jobs and run durable workflows for all sorts of background tasks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even with all their great features, Cloudflare Workers do have some limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Language Support:&lt;/strong&gt; They mainly support JavaScript and TypeScript, plus languages compiled to WASM. But their native language support isn&amp;#39;t as wide as Lambda@Edge&amp;#39;s broader range.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource Limits:&lt;/strong&gt; There are resource limits. Memory is fixed at 128MB, unlike Lambda&amp;#39;s adjustable memory up to 10GB. The most CPU time you get per request is 10ms on the free plan and 30 seconds on the paid plan, with a default timeout of 30 seconds (though it can go up to 5 minutes for paid plans, or 15 minutes for cron/queue triggers).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ecosystem Integration:&lt;/strong&gt; When it comes to ecosystem integration, Workers work really well with Cloudflare&amp;#39;s own developer services (like Workers KV, R2, D1, and Durable Objects). But connecting them with outside cloud services, like AWS&amp;#39;s huge ecosystem, can sometimes need a bit more setup, though things like Workers VPC are trying to make this easier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node.js Module Compatibility:&lt;/strong&gt; And for Node.js module compatibility, since Workers aren&amp;#39;t built on Node.js, some Node.js-specific packages might not work directly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cloudflare Workers really show what a &amp;quot;network-as-a-platform&amp;quot; means. Cloudflare started out with &lt;strong&gt;CDN&lt;/strong&gt; and DDoS protection so Workers run on their huge global network with over 330 data centers. When you add in services like R2 (edge storage) and D1 (edge database), it&amp;#39;s clear their strategy is to weave computing, storage, and security right into their global &lt;strong&gt;CDN&lt;/strong&gt; setup. This gives you an amazing level of global reach and performance tuning. It&amp;#39;s perfect for apps that need to be truly &amp;quot;everywhere&amp;quot; without a lot of fuss. This way of doing things offers a strong alternative to traditional cloud-focused models, especially for web apps, by making the network edge the main place for computing and data processing, not just a caching spot.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Head-to-Head: AWS Lambda@Edge vs. Cloudflare Workers&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;When we compare &lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt; and &lt;strong&gt;Cloudflare Workers&lt;/strong&gt;, you&amp;#39;ll notice some big differences in performance, pricing, their ecosystems, and how easy they are for developers to use. Knowing these differences is super important for picking the right &lt;strong&gt;edge computing&lt;/strong&gt; solution for your app&amp;#39;s specific needs.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Performance: How Fast Are They?&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt; are usually known for their amazing cold start performance. They often hit near-zero or even 0ms cold starts because of how their V8 isolate runtime works. This means your functions are ready to go almost instantly, giving you really consistent, &lt;strong&gt;low-latency&lt;/strong&gt; responses. Tests often show Workers beating Lambda@Edge in initial load times and at the higher end of response times.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt;, even though it&amp;#39;s much better than regular AWS Lambda, can still have cold starts, especially for functions you don&amp;#39;t use very often. While it can perform well, its consistency might not be as good as Workers. For pure execution speed, CloudFront Functions (a lighter AWS edge option) can run in under 1 millisecond, but Lambda@Edge is billed in 50ms chunks. This suggests it has a bit more overhead compared to Workers&amp;#39; V8 isolates.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;How Do They Charge You?&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;The way these two platforms charge you is quite different.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt; charges you based on how many requests you make and how long your code runs, measured in GB-seconds. You&amp;#39;ll pay $0.60 for every 1 million requests, and the duration costs are $0.00005001 per GB-second. Your costs can change a lot depending on how you use it, especially with data transfer fees, which are just regular AWS data transfer charges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt; have a more predictable pricing model. They offer a pretty generous free tier (100,000 requests per day, 10ms CPU time per request) and a paid plan that starts at $5 a month. That paid plan includes 10 million requests and 30 million CPU milliseconds. If you need more, extra requests are $0.30 per million, and CPU time is $0.02 per million CPU milliseconds. And here&amp;#39;s a big one: Cloudflare doesn&amp;#39;t charge you for data leaving their network (egress) for Workers.&lt;/p&gt;
&lt;p&gt;This difference in how they charge can really affect your budget and how you try to save money. Cloudflare&amp;#39;s pricing is set up to give you more certainty, which is great for startups and businesses with lots of steady traffic, where those data transfer fees from traditional clouds can become a big, hidden cost. AWS does have a free tier, but your bills can vary more, especially as data transfer costs add up across different services. If your app sends out a lot of data or has unpredictable traffic spikes, Cloudflare&amp;#39;s approach might give you a better overall cost.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a simple look at their pricing:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cost Factor&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AWS Lambda@Edge (Example Rates)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cloudflare Workers (Paid Plan Example Rates)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Requests&lt;/td&gt;
&lt;td&gt;$0.60 per 1 million requests&lt;/td&gt;
&lt;td&gt;$0.30 per 1 million requests (after 10M included)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duration (Compute Time)&lt;/td&gt;
&lt;td&gt;$0.00005001 per GB-second&lt;/td&gt;
&lt;td&gt;$0.02 per million CPU milliseconds (after 30M included)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Transfer (Egress)&lt;/td&gt;
&lt;td&gt;Standard AWS data transfer fees apply&lt;/td&gt;
&lt;td&gt;No egress fees&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h4&gt;&lt;strong&gt;Language Support &amp;amp; Runtime Environment&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt; works with Node.js and Python. Its functions run inside a container-based environment, which gives you flexibility in how you give them resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt; mainly support JavaScript and TypeScript, plus languages compiled to WASM like Rust, Go, or Python using a special interface. Their code runs on the Chrome V8 Engine, using those isolates we talked about. The fact that we keep talking about V8 isolates for Cloudflare Workers versus Node.js/Python containers for Lambda@Edge really highlights a basic difference in how these platforms handle &lt;strong&gt;serverless&lt;/strong&gt; code. Cloudflare picked V8 isolates because they want to get the best cold start performance and be super efficient with resources. AWS&amp;#39;s container approach, while it gives you more language options and resource control, naturally comes with some cold start overhead. This difference in design directly affects what kind of tasks each platform is best for, because the runtime choice determines how cold starts behave, and that shapes the best uses. Cloudflare focuses on speed and consistency, while AWS focuses on wider compatibility and working closely with its existing cloud services.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Ecosystem &amp;amp; Integrations&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt; is really well connected with the huge AWS ecosystem. This includes services like S3, DynamoDB, API Gateway, and &lt;strong&gt;IoT&lt;/strong&gt; Core. This means you get super smooth connections for building complex apps that use many different services within the AWS cloud.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt; fit perfectly with Cloudflare&amp;#39;s own developer services, like Workers KV (a &lt;strong&gt;low-latency&lt;/strong&gt; key-value store), R2 (object storage with no data transfer fees), D1 (a &lt;strong&gt;serverless&lt;/strong&gt; SQL database), Durable Objects (for storing state), and Workers AI. But connecting them with outside cloud services, like AWS&amp;#39;s huge ecosystem, can sometimes need a bit more setup, though things like Workers VPC are trying to make this easier.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Use Case Suitability&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt; usually works better for complex tasks that need to connect deeply with AWS services. Think custom security and login rules, dynamic content for different users, and backend processing that can use other AWS resources. It&amp;#39;s a great pick if your organization already uses a lot of AWS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt; really shine with high-frequency, &lt;strong&gt;low-latency&lt;/strong&gt; tasks, changing data in real-time, making APIs faster, A/B testing, and serving dynamic front-ends. They&amp;#39;re especially good for apps where consistent global performance and almost no cold starts are super important, and for those who want predictable pricing and don&amp;#39;t want to be tied to one vendor.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Developer Experience &amp;amp; Tooling&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;How easy they are to use for developers also differs between the two.&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt;, you&amp;#39;ll mostly manage development through the AWS Lambda console, and deployments are linked to CloudFront&amp;#39;s global rollout, which can take some time. For finding and fixing bugs, you&amp;#39;ll mostly rely on CloudWatch logs, and tools like AWS SAM CLI can help you test things locally.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt; give you a more integrated developer experience with their wrangler command-line tool. It helps with local development, live reloading, testing, and deploying your code. They also work well with popular frontend frameworks like Vite and have a dedicated Discord server for community support. AWS Lambda has been around longer, so it has a huge collection of tools and resources, thanks to being one of the first in the &lt;strong&gt;serverless&lt;/strong&gt; world. Cloudflare Workers are newer, but their developer community is growing fast and is very active.&lt;/p&gt;
&lt;p&gt;Beyond just how fast they are or what features they have, the &amp;quot;developer experience&amp;quot; is a big deal, and it&amp;#39;s often overlooked when people pick a platform. If you have a smoother process for developing, testing, and deploying locally, you can move faster, get more done, and ultimately get your apps to market quicker. Cloudflare seems to have put a lot of effort into making this part really good. A better developer experience can mean developers work faster and are happier, which then helps you innovate quicker and build stronger apps. This shows that ease of use and good tools aren&amp;#39;t just nice-to-haves; they&amp;#39;re actually key differences.&lt;/p&gt;
&lt;p&gt;Here is a comparison table summarizing the key features:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cold Start Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Potential for cold starts (faster than standard Lambda)&lt;/td&gt;
&lt;td&gt;Near-zero cold starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Runtime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Node.js/Python (container-based)&lt;/td&gt;
&lt;td&gt;V8 Isolates (JavaScript/TypeScript)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Language Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Node.js, Python&lt;/td&gt;
&lt;td&gt;JavaScript, TypeScript (WASM for others)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Global Network&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Global (via CloudFront Regional Edge Caches)&lt;/td&gt;
&lt;td&gt;Truly Global (330+ PoPs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pricing Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Per request + duration (GB-seconds)&lt;/td&gt;
&lt;td&gt;Per request + CPU time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Egress Fees&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (standard AWS data transfer)&lt;/td&gt;
&lt;td&gt;No (for Workers)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max Execution Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 5 minutes (origin response)&lt;/td&gt;
&lt;td&gt;30s (default, up to 5/15 min on paid)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 10GB&lt;/td&gt;
&lt;td&gt;Fixed 128MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Key Integrations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deep AWS services integration (S3, DynamoDB, IoT Core)&lt;/td&gt;
&lt;td&gt;Cloudflare Developer Platform (KV, R2, D1, Durable Objects)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complex AWS-integrated workloads, existing AWS users&lt;/td&gt;
&lt;td&gt;High-frequency, &lt;strong&gt;low-latency&lt;/strong&gt; web/API, real-time edge logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;&lt;strong&gt;Frequently Asked Questions: Your Edge Computing Dilemmas Solved&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;When you&amp;#39;re trying to pick between these powerful &lt;strong&gt;edge computing&lt;/strong&gt; platforms, you&amp;#39;ll probably have some common questions. Here are answers to some of those tricky situations.&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;When should you pick AWS Lambda@Edge instead of Cloudflare Workers?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;You should go with Lambda@Edge if your app already uses a lot of AWS services. If you need to talk to other AWS services like S3, DynamoDB, or &lt;strong&gt;IoT&lt;/strong&gt; Core often and smoothly, Lambda@Edge gives you unmatched integration and a development environment you&amp;#39;re probably already used to. It&amp;#39;s also a solid choice if your edge functions need more memory (up to 10GB) or longer run times (up to 5 minutes for some events). If you really want fine-grained control and lots of customization within the AWS system, Lambda@Edge is probably your best bet.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;When should you pick Cloudflare Workers instead of AWS Lambda@Edge?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;You should go with Cloudflare Workers when super-low &lt;strong&gt;latency&lt;/strong&gt; and consistently near-zero &amp;quot;cold start&amp;quot; performance are absolutely essential, especially for web apps or APIs that users interact with a lot. Its V8 isolate runtime pretty much gets rid of cold starts, so you get instant responses worldwide. Cloudflare Workers are also great if you want predictable pricing with no data transfer fees, because that can save you a lot of money for high-traffic apps. If your main goal is to make web and API performance faster globally with a light, JavaScript-focused approach, or if you prefer a platform that naturally uses a huge global network for distribution, Workers are an excellent choice.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can you use both AWS and Cloudflare at the same time?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Totally! Many organizations successfully use a mix-and-match approach, taking the best parts of both platforms. You can use Cloudflare&amp;#39;s &lt;strong&gt;CDN&lt;/strong&gt; and Workers for speeding up your front-end, balancing traffic globally, and edge security, while keeping your heavier backend stuff (like databases, complex microservices, and machine learning tasks) in AWS. This combo often gives you a better user experience and helps you save money. The cloud world is moving past just picking &amp;quot;either/or&amp;quot; to choosing the &amp;quot;best tool for the job.&amp;quot; For many complex apps, combining a full-service cloud provider like AWS (for deep backend stuff) with an edge-focused platform like Cloudflare (for global performance and security) is becoming the smartest way to go. This means architects and developers should think about using multiple clouds and hybrid setups from the start, focusing on how things work together and figuring out which tasks are best for the main cloud and which need edge processing.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What about &amp;#39;cold starts&amp;#39; – do they really matter that much?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cold starts are basically that delay you get when a &lt;strong&gt;serverless&lt;/strong&gt; function runs for the first time or after it&amp;#39;s been idle. They can add a noticeable pause, sometimes over a second, to user requests, especially for functions that aren&amp;#39;t used very often. For apps where every millisecond counts, like real-time games or interactive dashboards, cold starts can really mess up the user experience. Cloudflare Workers largely avoid this problem because of their V8 isolate design, which makes them perfect for those situations. While AWS Lambda@Edge has gotten better at cold starts, it still has these delays, making it less consistent for very sensitive, bursty tasks.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do their developer tools stack up?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;The developer tools and overall experience are different for each platform. For AWS Lambda@Edge, you&amp;#39;ll mostly develop through the AWS Lambda console, and deployments are linked to CloudFront&amp;#39;s global rollout, which can take a bit of time. When you&amp;#39;re debugging, you&amp;#39;ll mostly use CloudWatch logs, and tools like AWS SAM CLI can help you test things locally. Cloudflare Workers give you a more integrated developer experience with their wrangler command-line tool. It helps with local development, live reloading, testing, and debugging. They also work well with popular frontend frameworks and have a dedicated Discord server for community support. AWS Lambda has been around longer, so it has a huge collection of tools and resources, thanks to being one of the first in the &lt;strong&gt;serverless&lt;/strong&gt; world. Cloudflare Workers are newer, but their developer community is growing fast and is very active.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h3&gt;&lt;strong&gt;The Future is at the Edge: Making Your Decision&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;There&amp;#39;s no doubt that we&amp;#39;re moving towards &lt;strong&gt;edge computing&lt;/strong&gt;. It&amp;#39;s all thanks to the growing need for &lt;strong&gt;low-latency&lt;/strong&gt; apps, better security, and efficient data processing, especially with all the &lt;strong&gt;IoT&lt;/strong&gt; devices out there. Both &lt;strong&gt;AWS Lambda@Edge&lt;/strong&gt; and &lt;strong&gt;Cloudflare Workers&lt;/strong&gt; offer great solutions, and each has its own strong points. There isn&amp;#39;t one &amp;quot;better&amp;quot; &lt;strong&gt;edge computing&lt;/strong&gt; platform for everyone. The best choice really depends on what you&amp;#39;re trying to do, what tech you&amp;#39;re already using, what performance you need most, and what your budget looks like. This means you&amp;#39;ll need to think carefully, not just pick one size fits all. You&amp;#39;ll want to really understand what your app needs before you choose an edge platform.&lt;/p&gt;
&lt;p&gt;Here are some key things to think about when you&amp;#39;re deciding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Existing Infrastructure:&lt;/strong&gt; What infrastructure do you already have? If you&amp;#39;re already using a lot of AWS, Lambda@Edge will feel like a natural fit, connecting smoothly with your existing AWS services. But if you&amp;#39;re starting fresh or want to use multiple clouds, Cloudflare Workers might be more attractive because it doesn&amp;#39;t tie you to one vendor and has a huge network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Latency Requirements:&lt;/strong&gt; How much &lt;strong&gt;latency&lt;/strong&gt; can you handle? For apps where every millisecond matters and cold starts are a no-go like real-time user interactions or gaming Cloudflare Workers&amp;#39; V8 isolates give you a consistent advantage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workload Complexity and Statefulness:&lt;/strong&gt; How complex is your workload, and does it need to remember things (statefulness)? If your edge functions need to do complex calculations, talk to lots of different backend services, or keep track of information across requests, Lambda@Edge&amp;#39;s wider language support and deeper AWS integration might be a better fit. Cloudflare Workers are great for simple, stateless tasks or basic stateful logic using their built-in KV or Durable Objects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pricing Predictability vs. Granularity:&lt;/strong&gt; Do you want predictable pricing or more control over details? Cloudflare gives you more predictable, flat-rate pricing with no data transfer fees, which is perfect for clear budgeting. AWS Lambda@Edge uses a pay-as-you-go model that can vary more, but it gives you very fine control over how you allocate resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Developer Preference and Tooling:&lt;/strong&gt; Think about what your developers prefer and what tools they use. You should also consider which platform&amp;#39;s development process, language support, and tools work best with your team&amp;#39;s skills and preferences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security and Compliance Needs:&lt;/strong&gt; What about security and compliance? Both platforms have strong security features. Cloudflare offers built-in DDoS protection and a Web Application Firewall (WAF) that&amp;#39;s easy to set up, while AWS gives you detailed control and works with its wide range of security services.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The word &amp;quot;edge&amp;quot; itself can mean different things. AWS Lambda@Edge works at what you might call the &amp;quot;regional edge&amp;quot; within AWS, giving you much better &lt;strong&gt;latency&lt;/strong&gt; than central regions. Cloudflare Workers, though, by using its huge global network of over 330 Points of Presence (PoPs) and those V8 isolates, pushes computing even further to the &amp;quot;deep edge,&amp;quot; much, much closer to where the user is. This tells us there&amp;#39;s a constant push to get computing closer and closer to the user, driven by the growing need for real-time apps and the explosion of &lt;strong&gt;IoT&lt;/strong&gt; devices. Future breakthroughs in &lt;strong&gt;edge computing&lt;/strong&gt; will probably focus on even&lt;/p&gt;
</content:encoded><category>Edge Computing</category><category>AWS Lambda</category><category>Cloudflare</category><category>Serverless</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0098-edge-computing-aws-lambda-at-edge-vs-cloudflare-workers-practical-guide/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Navigating the Future of Cloud with Multi-Cloud IaC: Pulumi and Crossplane</title><link>https://mkabumattar.com/blog/post/multi-cloud-iac-pulumi-crossplane-future-cloud/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/multi-cloud-iac-pulumi-crossplane-future-cloud/</guid><description>Explore multi-cloud Infrastructure as Code with Pulumi and Crossplane. Learn how these tools enhance agility, reduce vendor lock-in, and shape the future of cloud management.</description><pubDate>Sat, 28 Feb 2026 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;strong&gt;Why Are Organizations Embracing Multi-Cloud Strategies?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Organizations are really getting into multi-cloud these days. Instead of sticking with just one cloud provider, they&amp;#39;re using a mix of platforms like Amazon Web Services (AWS), Microsoft Azure, and Google Cloud Platform (GCP). This big shift is happening because it offers some pretty great benefits that help businesses meet their current needs and prepare for the future.&lt;/p&gt;
&lt;p&gt;One of the main reasons companies go multi-cloud is to avoid getting stuck with a single vendor. If you&amp;#39;re tied to just one provider, you might find yourself limited in terms of flexibility, how much you can negotiate on price, and even what services you can use. With a multi-cloud setup, you can spread out your work and data, so you&amp;#39;re not dependent on one vendor&amp;#39;s pricing or service limits. It&amp;#39;s not just about having a backup; it&amp;#39;s a smart move to get an edge on the competition. You get to pick the best services from each provider instead of settling for a single provider&amp;#39;s all-in-one package, which might not be perfect for everything. This way of choosing exactly what you need really changes how companies think about their cloud infrastructure.&lt;/p&gt;
&lt;p&gt;Plus, putting your applications and data across different clouds makes things much more reliable and available. If one cloud goes down, your important operations can smoothly switch over to another, keeping things running and minimizing disruptions. This is super important for good disaster recovery planning, giving you a strong safety net against unexpected problems.&lt;/p&gt;
&lt;p&gt;Multi-cloud also lets organizations pick services from different vendors, which can help them get better prices and lower their overall costs. This means companies can choose more affordable options after looking closely at costs versus performance, helping them avoid the downsides of one provider&amp;#39;s pricing structure. Beyond saving money directly, being more agile and flexible by using multiple cloud providers means businesses can find the best solutions for specific tasks. This helps them quickly adjust to new needs and encourages new ideas. That flexibility is key for trying out different services and technologies without being held back by one vendor&amp;#39;s system.&lt;/p&gt;
&lt;p&gt;A multi-cloud strategy lets businesses customize their service choices to fit their unique operational needs. You can literally pick and choose specific services from different providers that best match your business goals. For example, a company might use GCP for its advanced Artificial Intelligence (AI) features while using AWS for its strong computing services. This ability to select &amp;quot;best-of-breed&amp;quot; services makes your cloud setup work perfectly for your specific tasks. Also, putting cloud services closer to your users by using different geographic regions from multiple providers can really cut down on delays, giving you better connections and a smoother experience for users. Edge computing helps even more by processing data closer to where it&amp;#39;s created, making applications respond faster. Finally, multi-cloud setups are becoming super important for meeting various rules and regulations. They let organizations store and process data in specific areas to follow data sovereignty laws and other requirements more easily.&lt;/p&gt;
&lt;p&gt;Moving to multi-cloud isn&amp;#39;t just a technical choice; it&amp;#39;s a strategic one. It&amp;#39;s all about getting more control, making things more resilient, and staying competitive in today&amp;#39;s digital world. Here&amp;#39;s a quick look at the main benefits and challenges of going multi-cloud:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Aspect&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Challenges&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Strategic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Avoids Vendor Lock-in, Tailored Service Selection, More Agility/Flexibility&lt;/td&gt;
&lt;td&gt;More Complex, Integration Issues, Need for Skilled People, Slower Rollouts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operational&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Better Reliability/Redundancy, Less Latency&lt;/td&gt;
&lt;td&gt;Performance Bottlenecks, Network Delays/Bandwidth, Security Worries, Cost Management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compliance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Helps Meet Regulations&lt;/td&gt;
&lt;td&gt;Policies Can Get Messy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;What Challenges Does Multi-Cloud Introduce?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While multi-cloud offers some great advantages, it&amp;#39;s not without its tricky parts. Setting up and running a multi-cloud environment brings a whole new set of challenges that organizations really need to think about to get the most out of it.&lt;/p&gt;
&lt;p&gt;Managing multiple cloud platforms naturally makes things more complicated, both in how you design your systems and how you run them. This is because each cloud provider has its own interfaces, rules, and ways of doing things. Keeping everything running smoothly and consistently across these different environments takes careful planning and coordination. This added complexity can also mean it takes longer to get things up and running and to deploy new features across different systems if you don&amp;#39;t have the right tools and strategy.&lt;/p&gt;
&lt;p&gt;Security becomes a bigger concern in a multi-cloud setup. When your operations are spread out, there are more places for attacks to happen, and your security rules can get fragmented if you&amp;#39;re not careful. It&amp;#39;s really important to make sure you have strong and consistent security across all platforms, including using &amp;quot;Zero Trust&amp;quot; models where everyone accessing network resources needs to be verified. There&amp;#39;s also a higher risk of &amp;quot;Shadow IT,&amp;quot; which is when people use unauthorized cloud services.&lt;/p&gt;
&lt;p&gt;Making sure data and workflows move smoothly across different cloud platforms is a big hurdle. You need to ensure that different systems and clouds can work together easily (interoperability) and that your data stays accurate and reliable across all environments. This calls for a smart approach to how you manage data and deploy applications across these diverse setups.&lt;/p&gt;
&lt;p&gt;The complexity of multi-cloud systems means you need specialized and well-trained people. Understanding the ins and outs of different cloud platforms and managing them effectively requires a lot of expertise and experience. The learning curve for new tools and processes can be steep, especially if your teams aren&amp;#39;t strong in developer skills. The constant mention of needing skilled people tells us that human talent is a huge, often overlooked, challenge in adopting multi-cloud. It&amp;#39;s not just about finding folks with specific cloud certifications; it&amp;#39;s about building teams that can handle the challenges of getting different systems to work together. So, if you&amp;#39;re going multi-cloud, you&amp;#39;ll need to invest a lot in training your current teams or hiring new talent. And when you pick Infrastructure as Code (IaC) tools, think about how well they fit with your team&amp;#39;s current programming skills to make that learning curve easier.&lt;/p&gt;
&lt;p&gt;Working across multiple clouds can also lead to slower network speeds and more bandwidth use, which can affect how well things perform and how users experience your services, especially when you need real-time data processing and quick responses. When you&amp;#39;re designing your systems, you really need to consider traffic between clouds, caching layers, and any potential delays if one system needs to take over for another.&lt;/p&gt;
&lt;p&gt;While multi-cloud strategies promise to save you money, they also bring challenges in managing those costs. Unpredictable expenses and the need for smart financial operations (FinOps) to track usage and allocate costs across providers are common issues. This shows that multi-cloud doesn&amp;#39;t automatically save you money; it only does if you manage it well. The real cost goes beyond just computing resources; it includes the effort of managing complexity, investing in skilled people, and getting specialized tools. So, companies need to invest in strong FinOps practices and automation tools right from the start to truly get the cost benefits of multi-cloud, instead of just assuming it&amp;#39;ll happen. Without this proactive approach, the complexity can quickly eat away at any potential savings.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How Does Infrastructure as Code (IaC) Revolutionize Cloud Management?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When you&amp;#39;re dealing with all that multi-cloud complexity, Infrastructure as Code (IaC) really steps up as a game-changer. It completely changes how organizations manage and set up their IT resources. By treating infrastructure configurations like software, IaC brings amazing levels of automation, consistency, and scalability to today&amp;#39;s IT environments.&lt;/p&gt;
&lt;p&gt;IaC is basically about managing and setting up computer data centers using machine-readable files. It replaces all the manual work you used to do for IT resource management and provisioning by simple lines of code. This approach has become super popular as systems get more complex, because trying to configure things manually just doesn&amp;#39;t cut it anymore.&lt;/p&gt;
&lt;p&gt;Here are the main ideas behind IaC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Version Control:&lt;/strong&gt; Just like with application code, your infrastructure code should live in a version control system, like Git. This lets your team keep track of changes over time, see who changed what and why, allows multiple people to work on it at once, and makes it easy to go back to a stable version of your infrastructure if something goes wrong.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Idempotency:&lt;/strong&gt; IaC scripts are designed to be &amp;quot;idempotent.&amp;quot; This means if you run them multiple times, you&amp;#39;ll get the same result as running them just once. For example, if a script is supposed to create a virtual machine (VM), running it again won&amp;#39;t create a duplicate VM; it&amp;#39;ll just see that the VM is already there and do nothing. This keeps things consistent and prevents accidental changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automation and Orchestration:&lt;/strong&gt; At its heart, IaC turns your infrastructure into code, which means you can automate its entire life cycle. This includes setting up, configuring, updating, and even getting rid of resources. Orchestration takes automation a step further by coordinating many automated tasks, making complex deployments much smoother.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistency and Repeatability:&lt;/strong&gt; IaC helps keep things consistent across different environments, like development, testing, and production. You use the same code to deploy infrastructure everywhere, which cuts down on environment-specific problems and makes things reliable at scale. This consistency also means you can rebuild entire environments from scratch with confidence, which is incredibly useful for testing, fixing problems, and recovering from disasters.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The benefits of using IaC are huge. It makes things much faster and more consistent, cutting deployment times from hours to minutes without sacrificing security. This means you can make changes more quickly and ensure tasks are done reliably, since you&amp;#39;re not waiting on manual processes. By getting rid of human errors that come from manual configurations, IaC significantly reduces mistakes and makes infrastructure deployments more consistent. This reliability in setting up infrastructure lets developers focus more on building applications, because they can write infrastructure code once and reuse it many times, thus, saving time and effort. IaC can also lower management overhead by removing the need for many administrative roles focused on managing different hardware and software layers, freeing up people for more important tasks. Plus, IaC makes security better by moving from just checking things after they&amp;#39;re done to actively enforcing rules. IaC templates can include compliance requirements and security checks, looking for vulnerabilities before you even set things up and even automatically stopping infrastructure that doesn&amp;#39;t follow best practices.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a simple example of what IaC might look like, defining a basic cloud server:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# This is a generic IaC example, showing how you define infrastructure as code.
# The exact syntax would vary depending on the IaC tool (e.g., Terraform, CloudFormation).

# Define a virtual server
resource &amp;quot;server&amp;quot; &amp;quot;web_server&amp;quot; {
  name        = &amp;quot;my-web-server&amp;quot;
  region      = &amp;quot;us-east-1&amp;quot;
  instance_type = &amp;quot;t2.micro&amp;quot;
  image_id    = &amp;quot;ami-0abcdef1234567890&amp;quot; # Example AMI ID
  tags = {
    Environment = &amp;quot;Development&amp;quot;
    Project     = &amp;quot;BlogPost&amp;quot;
  }
}

# Define a network security group (firewall rules)
resource &amp;quot;security_group&amp;quot; &amp;quot;web_server_sg&amp;quot; {
  name        = &amp;quot;web-server-security-group&amp;quot;
  description = &amp;quot;Allow HTTP and SSH access&amp;quot;

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = &amp;quot;tcp&amp;quot;
    cidr_blocks = [&amp;quot;0.0.0.0/0&amp;quot;] # Allow HTTP from anywhere
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = &amp;quot;tcp&amp;quot;
    cidr_blocks = # Allow SSH only from your IP
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IaC also lets you use variables to make your code flexible and reusable. This means you can define common settings once and then use them across different parts of your infrastructure or for different environments (like development vs. production).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# This is a generic IaC example showing how to use variables and outputs.
# Variables make your infrastructure code flexible and reusable.

variable &amp;quot;instance_type&amp;quot; {
  description = &amp;quot;The type of instance to deploy (e.g., t2.micro, m5.large)&amp;quot;
  type        = string
  default     = &amp;quot;t2.micro&amp;quot; # A default value if not specified
}

variable &amp;quot;environment_tag&amp;quot; {
  description = &amp;quot;Tag for the environment (e.g., dev, prod)&amp;quot;
  type        = string
}

resource &amp;quot;server&amp;quot; &amp;quot;my_server&amp;quot; {
  name        = &amp;quot;blog-server-${var.environment_tag}&amp;quot; # Using the environment_tag variable
  instance_type = var.instance_type # Using the instance_type variable
  #... other server configurations
  tags = {
    Environment = var.environment_tag
  }
}

# Outputs let you easily retrieve information about your deployed infrastructure.
output &amp;quot;server_name&amp;quot; {
  description = &amp;quot;The name of the deployed server&amp;quot;
  value       = resource.server.my_server.name
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To truly embrace multi-cloud with IaC, you&amp;#39;d define resources for different providers within your code. This conceptual example shows how you might define a virtual machine in AWS and a resource group in Azure, all within a single IaC approach:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# This is a conceptual multi-cloud IaC example.
# It shows how you might define resources for different cloud providers
# within a single Infrastructure as Code approach.

# AWS Virtual Machine Definition
resource &amp;quot;aws_instance&amp;quot; &amp;quot;my_aws_vm&amp;quot; {
  ami           = &amp;quot;ami-0abcdef1234567890&amp;quot; # Example AWS AMI ID
  instance_type = &amp;quot;t2.micro&amp;quot;
  region        = &amp;quot;us-east-1&amp;quot;
  tags = {
    Name        = &amp;quot;MultiCloud-AWS-VM&amp;quot;
    Environment = &amp;quot;Development&amp;quot;
  }
}

# Azure Resource Group Definition
resource &amp;quot;azurerm_resource_group&amp;quot; &amp;quot;my_azure_rg&amp;quot; {
  name     = &amp;quot;MultiCloud-Azure-RG&amp;quot;
  location = &amp;quot;East US&amp;quot; # Azure region
  tags = {
    Environment = &amp;quot;Development&amp;quot;
  }
}

# Note: The actual syntax and tool would vary (e.g., Terraform, Pulumi, CloudFormation).
# This example is for illustrative purposes to show multi-cloud definition in IaC.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you need to make a change to your infrastructure, IaC makes it straightforward. You simply update the code, and the IaC tool figures out what needs to be done to reach the new desired state. Here&amp;#39;s a conceptual example of updating the &lt;code&gt;web_server&lt;/code&gt; from &lt;code&gt;t2.micro&lt;/code&gt; to &lt;code&gt;t2.medium&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# This is a conceptual IaC update example.
# We&amp;#39;re updating the &amp;#39;instance_type&amp;#39; of our &amp;#39;web_server&amp;#39; from &amp;#39;t2.micro&amp;#39; to &amp;#39;t2.medium&amp;#39;.
# The IaC tool will detect this change and apply only what&amp;#39;s necessary.

# Define a virtual server
resource &amp;quot;server&amp;quot; &amp;quot;web_server&amp;quot; {
  name        = &amp;quot;my-web-server&amp;quot;
  region      = &amp;quot;us-east-1&amp;quot;
  instance_type = &amp;quot;t2.medium&amp;quot; # Changed from t2.micro
  image_id    = &amp;quot;ami-0abcdef1234567890&amp;quot;
  tags = {
    Environment = &amp;quot;Development&amp;quot;
    Project     = &amp;quot;BlogPost&amp;quot;
  }
}

# The rest of the configuration (like the security group) remains the same.
# The IaC tool&amp;#39;s &amp;quot;idempotency&amp;quot; ensures only the instance type is modified,
# not recreating the entire server or security group unnecessarily.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even with all its advantages, IaC does have some challenges. A big skill gap and potential resistance from teams can make it hard to adopt, especially since it requires a significant learning curve if teams aren&amp;#39;t used to coding languages like JSON, HCL, YAML, or Ruby. Older security tools and processes might not be enough for how dynamic IaC is, meaning you might need extra steps and new tools to set up safeguards and rules. Keeping an eye on IaC can also be tough, as tracking who sets up what, where, how often, and at what cost often needs additional, more dynamic tools beyond old-fashioned spreadsheets. Finally, while it&amp;#39;s helpful, IaC can get complicated for really large and intricate infrastructures, possibly needing advanced knowledge of the underlying technology.&lt;/p&gt;
&lt;p&gt;IaC isn&amp;#39;t just a &amp;quot;nice-to-have&amp;quot; in a multi-cloud world; it&amp;#39;s absolutely essential for making things efficient, secure, and scalable across different cloud environments. The benefits of IaC, like consistency, repeatability, and automation, directly tackle the main multi-cloud challenges, including complexity, integration problems, and messy policies. Without IaC, the inherent complexity of multi-cloud would probably overwhelm most organizations, turning a potentially chaotic mess into a controlled, well-managed landscape. This shift also means cloud professionals need new skills. The constant talk about a &amp;quot;skill gap&amp;quot; is directly linked to &amp;quot;coding language dependency&amp;quot;. This indicates a big change in what infrastructure professionals need to know: moving from manual configuration and graphical interface management to software development principles. Companies adopting IaC, especially in a multi-cloud setting, need to train their operations teams in software development practices or hire developers who understand infrastructure. This blurs the lines between traditional &amp;quot;Dev&amp;quot; and &amp;quot;Ops&amp;quot; roles and really strengthens the DevOps way of thinking.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Aspect&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Challenges&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Efficiency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automation, Faster Deployments, Fewer Errors, Efficient Software Development, Less Management Overhead&lt;/td&gt;
&lt;td&gt;Learning Curve/Skill Gap, Team Resistance, Monitoring Can Be Tricky&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Quality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Consistency, Repeatability, Better Security&lt;/td&gt;
&lt;td&gt;Security Checks Need Adapting, Complex for Big Systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Version Control, Track Changes, Easy Rollbacks&lt;/td&gt;
&lt;td&gt;Initial Setup Costs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;What is Pulumi and How Does It Empower Developers?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Pulumi is a modern take on Infrastructure as Code. What makes it stand out is that it lets developers define and manage cloud infrastructure using programming languages they already know. This really makes it easier for developers to get started and smoothly brings infrastructure management into their existing software development routines.&lt;/p&gt;
&lt;p&gt;Pulumi is an open-source IaC platform that lets DevOps teams and engineers use common programming languages like TypeScript, JavaScript, Python, Go,.NET, and Java to build, deploy, and manage cloud infrastructure like virtual machines, containers, and applications. Unlike older IaC tools that often rely on special languages (DSLs) or configuration files, Pulumi uses the full power of standard programming languages. This means developers can use regular coding practices like loops, functions, and if-then statements to create flexible and reusable configurations for their infrastructure, just like they would for their application code.&lt;/p&gt;
&lt;p&gt;For example, you can use a simple loop in Python with Pulumi to create multiple similar resources, which is something you&amp;#39;d typically do in application development:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import pulumi
import pulumi_aws as aws

# Define a list of bucket names we want to create
bucket_names = [&amp;quot;my-app-bucket-dev&amp;quot;, &amp;quot;my-app-bucket-staging&amp;quot;, &amp;quot;my-app-bucket-prod&amp;quot;]

# Loop through the list and create an S3 bucket for each name
for name in bucket_names:
    bucket = aws.s3.Bucket(name,
        bucket=name, # The actual bucket name in S3
        acl=&amp;quot;private&amp;quot;,
        tags={
            &amp;quot;Environment&amp;quot;: name.split(&amp;#39;-&amp;#39;)[-1].capitalize(), # Tag based on environment
            &amp;quot;Project&amp;quot;: &amp;quot;PulumiBlogLoop&amp;quot;
        })
    pulumi.export(f&amp;quot;{name}_id&amp;quot;, bucket.id) # Export each bucket&amp;#39;s ID
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s a simple Pulumi example in Python to create an AWS S3 bucket:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import pulumi
import pulumi_aws as aws

# Create an AWS S3 bucket
# This bucket will store objects and is configured for private access.
bucket = aws.s3.Bucket(&amp;quot;my-pulumi-bucket&amp;quot;,
    acl=&amp;quot;private&amp;quot;, # Access Control List: &amp;quot;private&amp;quot; means only the owner can access
    tags={ # Tags help organize and identify your resources
        &amp;quot;Environment&amp;quot;: &amp;quot;Development&amp;quot;,
        &amp;quot;Project&amp;quot;: &amp;quot;PulumiBlog&amp;quot;
    })

# Export the name of the bucket
# This makes the bucket name easily accessible after deployment.
pulumi.export(&amp;quot;bucket_name&amp;quot;, bucket.id)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To show Pulumi&amp;#39;s multi-cloud capabilities, here&amp;#39;s an example in TypeScript that creates an Azure Resource Group. Notice how the code structure remains familiar, even though it&amp;#39;s targeting a different cloud provider.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import * as azure_native from &amp;#39;@pulumi/azure-native&amp;#39;;
import * as pulumi from &amp;#39;@pulumi/pulumi&amp;#39;;

// Create an Azure Resource Group
// Resource Groups are logical containers for Azure resources.
const resourceGroup = new azure_native.resources.ResourceGroup(&amp;#39;my-azure-rg&amp;#39;, {
  resourceGroupName: &amp;#39;pulumi-blog-rg&amp;#39;, // Name of the resource group
  location: &amp;#39;EastUS&amp;#39;, // Azure region for the resource group
  tags: {
    // Tags for organization
    Environment: &amp;#39;Development&amp;#39;,
    Project: &amp;#39;PulumiBlog&amp;#39;,
  },
});

// Export the name of the resource group
pulumi.export(&amp;#39;resourceGroupName&amp;#39;, resourceGroup.name);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pulumi&amp;#39;s main strength is its support for many languages, giving engineers the freedom to pick the language they&amp;#39;re most comfortable with. This flexibility means you don&amp;#39;t have to learn special languages, which really cuts down on the time it takes to get started with new tools. Pulumi supports the whole infrastructure life cycle, including setting up, updating, and deleting resources, making sure things are consistent across different environments. Its Dynamic Provider feature lets you define and manage custom resources that aren&amp;#39;t directly supported by an existing Pulumi provider. This means you can create custom logic for pretty much any platform. Pulumi also encourages reusing code through its Pulumi Packages, letting developers define infrastructure building blocks and share them across teams. This helps keep things consistent and avoids doing the same work twice. By using the strong type checking features of the languages it supports, Pulumi helps prevent errors during deployment, offering a level of security and reliability you don&amp;#39;t always find in tools that use special languages. It also gives you great support in your code editor, with features like autocomplete and error checking, making the developer experience better. For handling sensitive information, Pulumi has strong built-in support through Pulumi ESC (Environment, Secrets, and Configuration), which encrypts secrets both when they&amp;#39;re moving around and when they&amp;#39;re stored. It also works with various external secret stores. What&amp;#39;s more, Pulumi automatically manages your infrastructure&amp;#39;s state, storing it securely in the Pulumi Cloud by default, with built-in state locking and encryption. You can also choose to use your own storage like AWS S3 or Azure Blob Storage. Pulumi also gives you real-time feedback by showing you changes before they&amp;#39;re deployed, which helps you avoid potential problems and make better decisions.&lt;/p&gt;
&lt;p&gt;Pulumi excels in multi-cloud setups, working with major cloud providers like AWS, Azure, Google Cloud, and over 150 others. This means you can manage infrastructure across these different environments using programming languages you already know. This capability is really important for avoiding vendor lock-in and staying flexible across different cloud systems.&lt;/p&gt;
&lt;p&gt;For organizations, Pulumi offers big advantages. By using familiar programming languages and software development methods, it helps developers write infrastructure code more efficiently, leading to faster development cycles and getting products to market quicker. Pulumi&amp;#39;s &amp;quot;infrastructure as software&amp;quot; approach improves teamwork between development, operations, and security teams through shared code repositories, code reviews, and automated testing. Developers get fine-grained control over infrastructure configurations, letting them customize resources for specific needs, which helps optimize performance, cost, and security. Importantly, by hiding the cloud provider-specific details, Pulumi reduces the risk of vendor lock-in, making it easier for organizations to switch providers or adopt a multi-cloud strategy with minimal hassle.&lt;/p&gt;
&lt;p&gt;The core innovation of Pulumi, using general-purpose programming languages, directly addresses the skill gap often found in IaC by making infrastructure management accessible to a broader pool of software developers who already know these languages. This suggests that the future of IaC is becoming more developer-focused, making true DevOps possible by letting the same teams and skills manage both application code and the underlying infrastructure. This leads to more connected development processes and potentially faster innovation. Also, while some IaC tools let you manage state yourself, Pulumi&amp;#39;s default to a managed service for state isn&amp;#39;t just convenient. It solves big operational problems like managing transactional state, locking state for multiple users, keeping a full deployment history, and encrypting state. This takes a lot of complexity and risk off your plate, especially in team environments. The trend toward managed services for IaC state shows that people are realizing state management is a complex, critical part of automating infrastructure that, if handled poorly, can lead to outages and security breaches. Relying on a managed service lets organizations focus on their main business instead of dealing with infrastructure plumbing.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What is Crossplane and Why is Kubernetes Its Native Home?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Crossplane has a unique way of doing Infrastructure as Code: it extends the Kubernetes control plane itself to manage external cloud infrastructure. This basically turns Kubernetes into a &amp;quot;universal control plane,&amp;quot; letting organizations set up and manage resources across many cloud providers using the Kubernetes-native tools and processes they&amp;#39;re already familiar with.&lt;/p&gt;
&lt;p&gt;Crossplane is an open-source Kubernetes add-on and cloud-native control plane that lets organizations manage and set up infrastructure across multiple cloud providers using Kubernetes-native APIs. It treats infrastructure like Kubernetes resources, so teams can define, deploy, and manage infrastructure using declarative configurations, just like they manage applications within Kubernetes. The project started at Upbound in 2018 and later joined the Cloud Native Computing Foundation (CNCF) in 2020, which shows its strong connection to cloud-native ideas.&lt;/p&gt;
&lt;p&gt;Crossplane&amp;#39;s main strength is its Kubernetes-native approach. It uses Kubernetes concepts like Custom Resource Definitions (CRDs) and controllers to really expand Kubernetes&amp;#39; ability to manage infrastructure resources. This means you can manage external resources, like servers and applications that aren&amp;#39;t traditionally part of a Kubernetes cluster, in the same way you manage pods and nodes. The core of Crossplane&amp;#39;s multi-cloud capabilities are its Providers. These are like plugins that let Crossplane talk to specific cloud services (like AWS, Azure, GCP) or other external systems. Each provider handles the logic needed to communicate with a particular cloud platform, which makes it easy to add new features to Crossplane.&lt;/p&gt;
&lt;p&gt;A key feature is Compositions, also called Composite Resource Definitions (XRDs). These are high-level blueprints that define reusable infrastructure templates. By using compositions, platform teams can give developers simpler ways to request infrastructure, shielding them from the complex cloud details and making sure everyone follows best practices, uses cost-effective setups, and keeps things consistent across different environments and teams. This turns a Kubernetes cluster into a central control point for managing not just resources inside the cluster but also external cloud services, making the management experience consistent for both applications and infrastructure. Crossplane also works perfectly with GitOps workflows, letting you manage infrastructure configurations using version control systems. This makes it easier to track changes, improves teamwork through familiar code review processes, and ensures your deployed infrastructure always matches what&amp;#39;s defined in your repository. Plus, Crossplane enables policy-driven infrastructure setup and governance by integrating Kubernetes-native Role-Based Access Control (RBAC) and letting you embed policies within compositions.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a simple Crossplane example in YAML to create an AWS S3 bucket:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# This is a Crossplane example in YAML, defining an AWS S3 bucket.
# Crossplane uses Kubernetes Custom Resource Definitions (CRDs) to represent cloud resources.

apiVersion: s3.aws.upbound.io/v1beta1 # API version for AWS S3 resources in Crossplane
kind: Bucket # The kind of resource we want to create: an S3 Bucket
metadata:
  name: my-crossplane-bucket # A unique name for our bucket
spec:
  forProvider: # These are the provider-specific configurations for the S3 bucket
    region: us-east-1 # The AWS region where the bucket will be created
    acl: private # Access Control List: &amp;quot;private&amp;quot; means only the owner can access
    tags: # Tags help organize and identify your resources
      Environment: Development
      Project: CrossplaneBlog
  providerConfigRef: # Reference to the Crossplane ProviderConfig, which holds AWS credentials
    name: default # Assumes you have a ProviderConfig named &amp;#39;default&amp;#39; set up for AWS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To illustrate Crossplane&amp;#39;s powerful abstraction capabilities, here&amp;#39;s a conceptual example of a &lt;code&gt;CompositeResourceDefinition&lt;/code&gt; (XRD) for a &amp;quot;ManagedDatabase.&amp;quot; This XRD defines a high-level database concept that platform teams can expose to developers, hiding the underlying cloud-specific details.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# This is a conceptual Crossplane CompositeResourceDefinition (XRD) example.
# It defines a high-level &amp;quot;ManagedDatabase&amp;quot; that abstracts away cloud-specific details.
# Platform teams create XRDs to offer simplified, reusable infrastructure blueprints.

apiVersion: apiextensions.crossplane.io/v1 # API version for Crossplane&amp;#39;s API extensions
kind: CompositeResourceDefinition # Defines a new kind of composite resource
metadata:
  name: manageddatabases.example.com # The name of our new composite resource
spec:
  group: example.com # The API group for this composite resource
  names:
    kind: ManagedDatabase # The user-friendly name for this resource
    plural: manageddatabases # The plural form for kubectl commands
  versions:
    - name: v1alpha1 # Version of this API
      served: true
      referenceable: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                parameters: # Parameters that developers can specify
                  type: object
                  properties:
                    storageGB:
                      type: integer
                      description: &amp;#39;Desired storage in GB.&amp;#39;
                    engine:
                      type: string
                      description: &amp;#39;Database engine (e.g., PostgreSQL, MySQL).&amp;#39;
                    version:
                      type: string
                      description: &amp;#39;Database engine version.&amp;#39;
              required:
                - parameters
      # This is where the magic happens: compositions define how this abstract
      # ManagedDatabase maps to actual cloud resources (e.g., AWS RDS, Azure Database).
      # The actual composition logic would be defined in a separate Composition resource.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once a platform team defines an XRD like &lt;code&gt;ManagedDatabase&lt;/code&gt;, application developers can then &amp;quot;claim&amp;quot; an instance of that database using a simpler &lt;code&gt;DatabaseClaim&lt;/code&gt; resource. This hides the complexity of the underlying cloud provider and specific database service.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# This is a conceptual Crossplane Claim example.
# Developers use Claims to request infrastructure defined by platform teams.
# This claim requests a &amp;quot;ManagedDatabase&amp;quot; instance.

apiVersion: example.com/v1alpha1 # Matches the group and version of the ManagedDatabase XRD
kind: DatabaseClaim # The kind of claim, as defined in the XRD&amp;#39;s claimNames
metadata:
  name: my-app-db-claim # A unique name for this specific database instance
spec:
  compositionSelector: # Optional: if there are multiple ways to fulfill the ManagedDatabase
    matchLabels:
      environment: development # Selects a composition optimized for development
  parameters: # Parameters passed to the ManagedDatabase
    storageGB: 50
    engine: PostgreSQL
    version: &amp;#39;14&amp;#39;
  # The actual connection details (e.g., host, port, credentials) would be
  # provisioned by Crossplane and typically stored in a Kubernetes Secret
  # that the application can then consume.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Crossplane excels in multi-cloud environments by providing a consistent way to manage resources across different providers (AWS, Azure, GCP, Alibaba Cloud) using a unified Kubernetes interface. This uniformity simplifies operations and reduces configuration errors. It helps you avoid vendor lock-in by offering a consistent way to interact with cloud services, no matter which cloud platform you&amp;#39;re using.&lt;/p&gt;
&lt;p&gt;For organizations, Crossplane offers unified infrastructure management by bringing together the management of cloud resources and applications under one Kubernetes interface. This makes self-service infrastructure possible, where platform engineering teams can create portals that let developers set up pre-approved environments without manual help. Crossplane also makes it easier to move workloads around by hiding the specific details of underlying cloud provider APIs, so applications and configurations can move between clouds with minimal changes. Through its continuous reconciliation model, Crossplane automatically finds and fixes any &amp;quot;configuration drift,&amp;quot; making sure the actual state always matches the desired state. Finally, it helps with cost management and FinOps by making consistent resource tagging possible for accurate cost tracking and by working with cloud-native cost management tools, which leads to better FinOps practices.&lt;/p&gt;
&lt;p&gt;Crossplane&amp;#39;s main idea of extending Kubernetes&amp;#39; control plane means a big change: Kubernetes isn&amp;#39;t just for orchestrating containers anymore. It&amp;#39;s becoming the go-to system for managing all cloud resources, both external and internal. For organizations that are heavily invested in Kubernetes, Crossplane offers a way to bring their entire cloud operational model together, simplifying tools and using existing Kubernetes expertise. This can lead to much more efficient operations and a more unified &amp;quot;cloud-native&amp;quot; experience. Also, Crossplane&amp;#39;s compositions and self-service provisioning capabilities point to a bigger trend in platform engineering: building Internal Developer Platforms (IDPs) that hide cloud complexity from application developers. Developers can use high-level &amp;quot;golden paths&amp;quot; without needing deep cloud-specific knowledge. This makes Crossplane a powerful tool for platform teams to become &amp;quot;product owners&amp;quot; of their internal cloud infrastructure, offering curated, compliant, and easy-to-use infrastructure services to their internal developer customers, thereby shifting the burden of cloud complexity from individual development teams to a specialized platform team.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Pulumi vs. Crossplane: Which IaC Tool Fits Your Strategy?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While both Pulumi and Crossplane are strong Infrastructure as Code tools designed to handle multi-cloud environments, they approach the problem from very different angles. Understanding these differences is key to picking the right tool that fits your organization&amp;#39;s current tech setup, team skills, and overall goals.&lt;/p&gt;
&lt;p&gt;Pulumi&amp;#39;s main idea is IaC that&amp;#39;s centered around programming languages. It brings infrastructure management into the familiar world of general-purpose programming languages like Python, TypeScript, Go,.NET, and Java. This lets developers use their existing coding skills to define and deploy infrastructure, making IaC a closer part of their usual development process. On the other hand, Crossplane&amp;#39;s main idea is a Kubernetes-native control plane. It extends Kubernetes to act as a control plane for infrastructure. Crossplane uses Kubernetes Custom Resource Definitions (CRDs) and the Kubernetes API to manage cloud resources, which makes infrastructure management smooth for teams already familiar with Kubernetes.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What Are the Best Practices for Multi-Cloud IaC Success?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Setting up multi-cloud Infrastructure as Code with tools like Pulumi and Crossplane needs more than just technical know-how. It requires a smart approach focused on best practices to get the most out of efficiency, security, cost control, and the developer experience.&lt;/p&gt;
&lt;p&gt;Basic IaC practices are super important. You should treat infrastructure code just like application code. This means all your IaC templates need to be stored in Git repositories so you can track changes, roll back errors, and work together effectively as a team. Setting up rules for branch protection and requiring pull requests for all infrastructure changes ensures that deployments are controlled and reviewed. Automating deployments through CI/CD pipelines (like Jenkins, GitLab CI, GitHub Actions) is crucial to kick off infrastructure updates whenever code is committed. Along with automation, you need to set up automated testing (unit, integration, and end-to-end) to check your infrastructure code before it&amp;#39;s deployed. This catches misconfigurations early in the development process. Also, break down complex infrastructure into reusable modules or components. This modular approach makes things easier to maintain and lets teams build complex environments from pre-tested building blocks. Putting documentation right into your IaC files ensures it stays up-to-date with code changes. Finally, embracing &amp;quot;immutable infrastructure,&amp;quot; where servers are treated as disposable resources and new instances with updates are deployed instead of patching existing ones, really cuts down on downtime and simplifies rollbacks.&lt;/p&gt;
&lt;p&gt;For multi-cloud and security-specific practices, being proactive is essential. You need to build security best practices and safeguards directly into your IaC process. This means integrating security scanning tools (like Checkov, Terrascan) into your CI/CD pipelines and using &amp;quot;policy-as-code&amp;quot; tools like Open Policy Agent (OPA) to enforce security rules and compliance requirements (like SOC2, HIPAA, PCI DSS, ISO27001, CIS). This &amp;quot;shift-left&amp;quot; approach to security makes sure that non-compliant deployments are stopped right from the start. Adopting a Zero Trust security model, which requires verification for all resource access no matter where it comes from, is also critical. Centralized Identity and Access Management (IAM) is another cornerstone; unifying IAM across multiple clouds using common standards like SAML or OAuth helps avoid vendor lock-in and simplifies user management. Implementing Single Sign-On (SSO) and Multi-Factor Authentication (MFA) further strengthens access control.&lt;/p&gt;
&lt;p&gt;Centralized monitoring and cost management (FinOps) are absolutely necessary. A single monitoring solution that gathers logs, metrics, and traces from all clouds makes troubleshooting easier and gives you real-time insights into performance. For cost management, adopting FinOps practices, standardizing provisioning with IaC templates, centralizing audit logging, applying consistent tagging and labeling across all providers, and enforcing least privilege access are key to optimizing spending. Finally, when picking cloud vendors, organizations need to have clear exit strategies. This means understanding termination conditions, help with moving data, and automatic renewal clauses to ensure smooth transitions if you ever need to switch.&lt;/p&gt;
&lt;p&gt;The focus on better security and building security best practices into IaC pipelines shows a shift: security isn&amp;#39;t an afterthought anymore; it&amp;#39;s a built-in part of how you define your infrastructure. For multi-cloud environments, where there are more places for attacks and policies can get messy, IaC becomes the main way to ensure consistent security and compliance at scale. This makes security a shared responsibility across development, operations, and security teams. Many of these best practices, such as breaking things into modules, customizable templates, centralized monitoring, and policy-as-code, are key parts of platform engineering. This suggests that successfully adopting multi-cloud IaC naturally pushes organizations toward building internal platforms that hide complexity and offer self-service capabilities. Organizations aiming for multi-cloud IaC success will likely find themselves moving toward a &amp;quot;platform team&amp;quot; model, where a dedicated group focuses on building reusable, compliant, and secure infrastructure components that other development teams can easily use. This is a strategic organizational change driven by the technical demands of multi-cloud.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What&amp;#39;s Next for Multi-Cloud IaC?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The world of multi-cloud Infrastructure as Code is always changing, driven by new technologies and the growing demands of digital transformation. Several upcoming trends are set to shape how organizations manage their various cloud environments in the future.&lt;/p&gt;
&lt;p&gt;Artificial Intelligence (AI) will play a bigger role in cloud security and automation. AI-driven insights will help automate security responses, spot unusual activity, optimize how resources are used, and predict potential problems across multi-cloud environments. Specifically, AI-driven insights will find old, unused infrastructure and help optimize costs, moving beyond just reacting to problems to actively making things better. This suggests that future multi-cloud IaC tools will increasingly include machine learning and AI features to provide autonomous infrastructure management, reducing manual work and maximizing efficiency and security, further empowering FinOps and platform engineering teams.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll see more advanced cloud marketplaces and pricing models based on how much you use. The explosion of services and flexible pricing across cloud providers will continue, meaning we&amp;#39;ll need more sophisticated IaC tools that can quickly adapt to cost-performance analyses and take advantage of competitive offers. Growing concerns about data sovereignty and global political factors will increase the demand for &amp;quot;sovereign cloud&amp;quot; solutions, where data stays within specific national borders. This will significantly impact multi-cloud strategies and IaC requirements for compliance. The mention of sovereign cloud and data sovereignty laws highlights that technical decisions in multi-cloud are increasingly influenced by non-technical, geopolitical factors. This adds a layer of complexity beyond just technical considerations like performance or cost. Multi-cloud IaC strategies will need to include advanced policy-as-code capabilities that can enforce geographical data residency and compliance requirements, becoming a critical component for organizations operating in regulated industries or across diverse international jurisdictions.&lt;/p&gt;
&lt;p&gt;The way cloud and edge computing come together will blur the lines between central data centers and distributed edge locations. Multi-cloud IaC will need to reach out and manage infrastructure across this whole spectrum, optimizing for less delay and localized processing. We might also see more highly specialized, industry-specific cloud solutions tailored to unique industry needs, like healthcare or finance. This will require IaC tools to work with these niche services while keeping multi-cloud consistency. Finally, the trend toward building Internal Developer Platforms (IDPs) will get even stronger, with IaC tools like Pulumi and Crossplane forming the backbone of these platforms. This will enable more self-service, standardization, and governance for developers. This ongoing evolution of platform engineering will be a key driver for multi-cloud IaC adoption and sophistication.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions (FAQs)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;This section answers common questions about multi-cloud IaC and the roles of Pulumi and Crossplane. We&amp;#39;ll give you clear and simple answers to help you understand these key concepts.&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What is vendor lock-in in multi-cloud, and how do IaC tools help avoid it?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Vendor lock-in happens when an organization is basically forced to keep using a product or service from one provider because it would be too expensive or difficult to switch. In cloud computing, this occurs when a platform or service only works with other offerings from the same vendor. Multi-cloud strategies, made easier by IaC tools like Pulumi and Crossplane, directly address this by letting organizations deploy and manage workloads across many providers. By hiding provider-specific details (Pulumi) or giving you a unified control plane (Crossplane), these tools reduce your reliance on any single vendor, giving businesses more freedom and flexibility.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Is IaC the same as DevOps?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, IaC and DevOps are related but they&amp;#39;re not the same thing. IaC is a core practice within DevOps. DevOps is a way of thinking and working that aims to bring software development (Dev) and IT operations (Ops) closer together. The goal is to speed up the software development life cycle and deliver high-quality software continuously. IaC helps make many DevOps principles possible by automating infrastructure setup, ensuring consistency, and allowing version control, which leads to faster deployments and better teamwork.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can Pulumi/Crossplane be used for on-premises infrastructure?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, both Pulumi and Crossplane can manage on-premises infrastructure, often as part of a hybrid cloud strategy. Pulumi supports hybrid cloud/on-premises resources and can use dynamic providers for services you host yourself. Crossplane, as a Kubernetes-native control plane, can extend to on-prem environments and manage resources there, especially when integrated with Kubernetes clusters running on-premises.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do Pulumi and Crossplane handle secrets management?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pulumi has strong built-in support for secrets management through Pulumi ESC (Environment, Secrets, and Configuration). It encrypts sensitive data both when it&amp;#39;s moving and when it&amp;#39;s stored, using Hardware Security Module (HSM)-based encryption. It can also pull and sync secrets from various external stores like HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, and 1Password. Crossplane doesn&amp;#39;t have a dedicated secrets management service like Pulumi ESC, but it uses Kubernetes secrets for storing credentials (like cloud provider API keys). This means you can use standard Kubernetes secret management practices and integrations with external secret stores through Kubernetes operators.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What kind of team expertise is needed for these tools?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pulumi is great for teams with strong programming skills (Python, TypeScript, Go, etc.) because it uses familiar software development workflows. It makes the learning curve easier for developers who already know these languages. Crossplane needs deep Kubernetes knowledge, including familiarity with CRDs, controllers, and Kubernetes-native tools. It&amp;#39;s best for organizations already heavily invested in the Kubernetes ecosystem. If you use both tools together, you&amp;#39;ll need expertise in both areas, often requiring a specialized &amp;quot;platform engineering&amp;quot; team to manage the integration and abstraction layers. The choice between Pulumi and Crossplane really depends on your team&amp;#39;s existing expertise and whether your organization is Kubernetes-centric. This highlights that your operational model and current organizational strengths are most important, rather than one tool being objectively &amp;quot;better.&amp;quot; Organizations shouldn&amp;#39;t just evaluate IaC tools based on features, but primarily on how well they fit with their current operational model, team capabilities, and strategic commitment to a particular control plane (like Kubernetes). A mismatch can lead to a lot of friction and make adoption difficult.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;Conclusion: Charting Your Course in the Multi-Cloud Landscape&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Moving into multi-cloud environments isn&amp;#39;t really an option for many organizations anymore; it&amp;#39;s a must-do. This is because businesses need resilience, cost savings, and amazing flexibility. But this journey can be complicated, from managing different interfaces to making sure security and compliance are consistent across all platforms. Infrastructure as Code (IaC) is the essential foundation for navigating this complex landscape, turning manual, error-prone tasks into automated, repeatable processes.&lt;/p&gt;
&lt;p&gt;Tools like Pulumi and Crossplane are at the forefront of multi-cloud IaC. Each offers unique strengths that fit different organizational needs. Pulumi empowers developers by letting them define infrastructure using programming languages they already know, smoothly bringing cloud management into their existing software development routines. This approach boosts productivity, teamwork, and gives you fine-grained control, making IaC accessible to more people. Crossplane, on the other hand, extends the power of Kubernetes, turning it into a universal control plane for managing all cloud resources through a unified, declarative API. This is perfect for Kubernetes-focused organizations looking to bring all their infrastructure management under one powerful orchestration layer, enabling self-service and strong policy enforcement.&lt;/p&gt;
&lt;p&gt;The most forward-thinking organizations are even looking at combining Pulumi and Crossplane. They use Pulumi to set up foundational Kubernetes clusters across different clouds, and then use Crossplane to manage cloud services within those clusters. While this layered approach adds a new level of operational complexity, especially when debugging issues that span both tools, it unlocks incredible scalability, reproducibility, and policy-driven governance. It&amp;#39;s truly the cutting edge of platform engineering.&lt;/p&gt;
&lt;p&gt;As the cloud ecosystem keeps changing rapidly, following multi-cloud IaC best practices – from strict version control and automated testing to building in security safeguards and adopting FinOps principles – will be crucial. The future of multi-cloud IaC promises even more automation and optimization through AI-driven insights, further blurring the lines between infrastructure and application development. By smartly adopting and integrating these powerful IaC tools, organizations can not only overcome the challenges of multi-cloud but also set themselves up for continuous innovation and a competitive edge in the dynamic digital world.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What is vendor lock-in? | Vendor lock-in and cloud computing - Cloudflare, accessed on June 6, 2025, &lt;a href=&quot;https://www.cloudflare.com/learning/cloud/what-is-vendor-lock-in/&quot;&gt;https://www.cloudflare.com/learning/cloud/what-is-vendor-lock-in/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;16 Most Useful Infrastructure as Code (IaC) Tools for 2025 - Spacelift, accessed on June 6, 2025, &lt;a href=&quot;https://spacelift.io/blog/infrastructure-as-code-tools&quot;&gt;https://spacelift.io/blog/infrastructure-as-code-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pulumi: A Modern Infrastructure as Code (IaC) Alternative to Terraform - Devtron, accessed on June 6, 2025, &lt;a href=&quot;https://devtron.ai/blog/introduction-to-pulumi-a-modern-infrastructure-as-code-platform/&quot;&gt;https://devtron.ai/blog/introduction-to-pulumi-a-modern-infrastructure-as-code-platform/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pulumi: Empowering Infrastructure Engineers with Real Programming Languages, accessed on June 6, 2025, &lt;a href=&quot;https://dev.to/fajmayor/pulumi-empowering-infrastructure-engineers-with-real-programming-languages-kp1&quot;&gt;https://dev.to/fajmayor/pulumi-empowering-infrastructure-engineers-with-real-programming-languages-kp1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform vs. Pulumi vs. Crossplane: Choosing the Right IaC Tool for Your Internal Developer Platform - DEV Community, accessed on June 6, 2025, &lt;a href=&quot;https://dev.to/romulofrancas/terraform-vs-pulumi-vs-crossplane-choosing-the-right-iac-tool-for-your-internal-developer-3a95&quot;&gt;https://dev.to/romulofrancas/terraform-vs-pulumi-vs-crossplane-choosing-the-right-iac-tool-for-your-internal-developer-3a95&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Modern Infrastructure as Code: OpenTofu vs. Crossplane vs. Pulumi - DEV Community, accessed on June 6, 2025, &lt;a href=&quot;https://dev.to/shashankpai/modern-infrastructure-as-code-opentofu-vs-crossplane-vs-pulumi-3gih&quot;&gt;https://dev.to/shashankpai/modern-infrastructure-as-code-opentofu-vs-crossplane-vs-pulumi-3gih&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Crossplane | Pulumi Docs, accessed on June 6, 2025, &lt;a href=&quot;https://www.pulumi.com/docs/iac/concepts/vs/crossplane/&quot;&gt;https://www.pulumi.com/docs/iac/concepts/vs/crossplane/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Revolutionizing Cloud Management: How Crossplane is Reshaping the Future of Infrastructure Management | Devoteam, accessed on June 6, 2025, &lt;a href=&quot;https://www.devoteam.com/expert-view/revolutionizing-cloud-management-how-crossplane-is-reshaping-the-future-of-infrastructure-management/&quot;&gt;https://www.devoteam.com/expert-view/revolutionizing-cloud-management-how-crossplane-is-reshaping-the-future-of-infrastructure-management/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Platform Engineering Simplified: The Power of Crossplane&amp;#39;s Nested Abstractions, accessed on June 6, 2025, &lt;a href=&quot;https://blog.upbound.io/platform-engineering-simplified&quot;&gt;https://blog.upbound.io/platform-engineering-simplified&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Automating Cloud Provisioning Using Pulumi and Crossplane - ResearchGate, accessed on June 6, 2025, &lt;a href=&quot;https://www.researchgate.net/publication/391015338_Automating_Cloud_Provisioning_Using_Pulumi_and_Crossplane&quot;&gt;https://www.researchgate.net/publication/391015338_Automating_Cloud_Provisioning_Using_Pulumi_and_Crossplane&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Multi-Cloud</category><category>Infrastructure as Code</category><category>Pulumi</category><category>Crossplane</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0097-multi-cloud-iac-pulumi-crossplane-future-cloud/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Building Resilient Systems: Immutable Infrastructure with Packer and Terraform</title><link>https://mkabumattar.com/blog/post/immutable-infrastructure-packer-terraform-guide/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/immutable-infrastructure-packer-terraform-guide/</guid><description>Discover how immutable infrastructure, powered by Packer and Terraform, transforms IT. Learn to build resilient, secure, and scalable systems by replacing, not updating, your infrastructure. This guide covers core concepts, hands-on workflows, and best practices for modern DevOps.</description><pubDate>Sat, 21 Feb 2026 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;strong&gt;What is Immutable Infrastructure?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The way we manage IT infrastructure has really changed. We&amp;#39;re moving from old-school, changeable setups to more modern, &amp;quot;immutable&amp;quot; ones. Understanding this big shift is super important if you want to build systems that are strong, can grow easily, and are secure in today&amp;#39;s cloud and DevOps world.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What Does &amp;quot;Immutable&amp;quot; Mean for Our IT Systems?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Simply put, immutable infrastructure is a strategy where once you deploy something like a server, a virtual machine (VM), or a container you never change it. Think of it like this: if you build a LEGO model, you don&amp;#39;t just swap out a few bricks to change it. Instead, you build a whole new, updated model and replace the old one. So, if you need to update a server, patch it, or change its settings, you don&amp;#39;t do it on the running system. You build a brand new version with all the changes, and then you swap out the old one. This &amp;quot;replace, don&amp;#39;t update&amp;quot; idea is a core part of the immutable approach.&lt;/p&gt;
&lt;p&gt;This idea actually comes from manufacturing. Imagine a factory that used to tweak machines on the assembly line. Now, they use single-use molds that are perfect every time. That made things more efficient, cut down on mistakes, and made production smoother. It&amp;#39;s the same in IT: immutable infrastructure gives us a structured way to manage servers with similar efficiency and reliability. Things like containers and VM images naturally fit this idea. If you need to change them, you usually create a new one instead of altering the existing one.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Mutable vs. Immutable Infrastructure: What&amp;#39;s the Difference?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The main difference between mutable and immutable infrastructure is how you handle your systems and updates.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;mutable infrastructure&lt;/strong&gt;, servers and their settings can change all the time. You might manually tweak things, apply patches, or install software updates directly on live systems. While this might seem flexible for quick fixes, it makes your systems less predictable and harder to secure. A big problem here is &amp;quot;configuration drift.&amp;quot; That&amp;#39;s when small, ongoing updates cause your environments to slowly become inconsistent over time, drifting away from what they were supposed to be. This can create &amp;quot;snowflake servers&amp;quot; unique machines with custom setups that are tough to figure out, manage, and reproduce. Debugging becomes a real headache because you don&amp;#39;t have clear versioning or predictable configurations.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;strong&gt;immutable infrastructure&lt;/strong&gt; handles changes by spinning up completely new servers or components that already have the updates you need. Then, you gracefully shut down the old servers and replace them with these new, updated versions. This makes sure your system is always in a known, stable, and version-controlled state. It really cuts down on unexpected problems that pop up from inconsistent environments. It also strictly separates deployment from runtime, guaranteeing that all changes show up as new, predictable instances. This way of working directly solves the common problem of configuration drift and those pesky snowflake servers. Since every instance is an exact copy of a version-controlled image, immutable infrastructure gets rid of a major source of operational chaos and security holes right from the start, instead of relying on constant, reactive management. The &amp;quot;replace, don&amp;#39;t update&amp;quot; rule is the direct answer to the &amp;quot;snowflake server&amp;quot; problem.&lt;/p&gt;
&lt;p&gt;This fundamental change in how we operate means teams need to learn new skills. Instead of spending time debugging live systems that might have undocumented changes, the focus shifts to debugging the image build pipelines and your infrastructure-as-code definitions. This impacts training, the tools you pick, and even how you respond to incidents. You&amp;#39;re moving from a reactive &amp;quot;fix-it-in-place&amp;quot; model to a proactive &amp;quot;rebuild-and-replace&amp;quot; one.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a quick comparison of the two ways to manage infrastructure:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Mutable Infrastructure&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Immutable Infrastructure&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Updates&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;In-place changes, patches, manual tweaks&lt;/td&gt;
&lt;td&gt;Replacement with new instances&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consistency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Prone to inconsistencies, configuration drift&lt;/td&gt;
&lt;td&gt;Very consistent, identical copies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration Drift&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High risk, common problem&lt;/td&gt;
&lt;td&gt;Eliminated by design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rollbacks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complex, manual, error-prone&lt;/td&gt;
&lt;td&gt;Simple, fast, redeploy previous version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Troubleshooting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hard (snowflake servers, untracked changes)&lt;/td&gt;
&lt;td&gt;Easier (known state, build-time validation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Higher attack surface (untracked changes, lingering vulnerabilities)&lt;/td&gt;
&lt;td&gt;Smaller attack surface (clean state, built-in security)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual scaling, can be inconsistent&lt;/td&gt;
&lt;td&gt;Better scalability, automated provisioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stateful Apps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Better for stateful/legacy (but with caveats)&lt;/td&gt;
&lt;td&gt;Tricky, needs externalized state or hybrid approach&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Why Embrace Immutable Infrastructure?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;People are adopting immutable infrastructure because it offers some really strong advantages. It makes things much better for security, reliability, how smoothly operations run, and how quickly your organization can adapt. All these benefits together help you build a more robust and predictable IT environment.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Does Immutable Infrastructure Make Things More Secure?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Immutable infrastructure gives you a solid way to improve your security. It naturally cuts down on security risks because you&amp;#39;re not making changes to running systems. Every new deployment starts from a clean, checked state. This actively stops attackers from using unpatched vulnerabilities or old, forgotten misconfigurations. If you find a security flaw, you don&amp;#39;t patch the running system; you deploy a new, secure version, which means the vulnerability is exposed for less time.&lt;/p&gt;
&lt;p&gt;This approach significantly reduces the &amp;quot;attack surface.&amp;quot; Your servers and services aren&amp;#39;t constantly exposed to risks from in-place changes that could accidentally introduce vulnerabilities. By frequently cycling through servers and infrastructure components, any potential security flaws exist for a shorter time before they&amp;#39;re replaced. This naturally works well with regular patching and updates. It&amp;#39;s a big shift from a reactive &amp;quot;patch-and-pray&amp;quot; security model to a proactive &amp;quot;rebuild-and-deploy-secure&amp;quot; one. Security measures are &amp;quot;baked in&amp;quot; right from when you create the image, not as an afterthought or an ongoing chore on running systems. This makes your systems more secure from the very beginning.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s more, immutable infrastructure makes compliance and auditing simpler. Since your infrastructure is defined as code and changes happen systematically through new deployments, you get a clear, auditable trail of all modifications made to the system. This transparency makes it much easier to check if you&amp;#39;re meeting regulatory standards and compliance rules. It also cuts down on administrative work and improves how you govern your IT systems overall. If a security incident happens, immutable infrastructure helps you recover fast and respond effectively. Because the system&amp;#39;s state is predefined and stored as code, administrators can quickly roll back to a previous good state without needing to diagnose and fix compromised parts. This minimizes downtime and the impact of cyberattacks. Privileged Access Management (PAM) becomes even more important here, as it helps make sure changes only happen through controlled, repeatable processes, giving you a clear and unchangeable audit trail of access and changes. This really boosts security and compliance.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What About Consistency and Reliability?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;A major plus of immutable infrastructure is the amazing consistency and reliability it brings to deployments. By treating each instance as having a version-controlled, predefined setup, it makes sure your environments are identical from development to testing to production. This directly gets rid of configuration drift, which is a common problem in traditional mutable systems where small updates lead to inconsistencies over time. Every deployment becomes consistent, predictable, and repeatable. That really cuts down on the risk of errors and inconsistencies across your environments. This consistency also means fewer deployment failures; by replacing systems entirely instead of changing them, immutable infrastructure removes the risk of failed updates due to old dependencies or unpredictable configurations.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Does It Make Operations Easier and Help with Scaling?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Immutable infrastructure naturally simplifies how you operate things. It does this by widely adopting automated, repeatable processes for setting up and deploying things, which drastically cuts down on the chance of human error. This approach works perfectly with Infrastructure as Code (IaC) strategies, letting you automate and repeat provisioning and scaling of resources. Plus, it makes horizontal scaling much easier. Your organization can quickly deploy more identical instances without needing to configure each one individually. This fits perfectly with how flexible cloud resources are and helps you respond quickly to changes in demand.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What Are the Advantages for Troubleshooting and Rollbacks?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The consistent nature of immutable infrastructure makes troubleshooting and rollbacks much, much simpler. Since every deployed instance is identical, figuring out problems becomes more straightforward. Instead of spending time diagnosing a broken system, your operational teams can just roll back to a previously known good state by redeploying a validated version. This leads to predictable upgrades, where rolling back and rolling out are as simple as launching an older image version to undo changes.&lt;/p&gt;
&lt;p&gt;This way of working also strongly supports advanced deployment strategies like blue-green deployments. In this model, you deploy a new version of your infrastructure right alongside the current one before you fully switch traffic over. This strategy means very little downtime and lets you thoroughly check updates before you retire the old instances. The ability to spin up a completely new, identical environment and then switch traffic is fundamentally possible because the underlying components are immutable. This shows that immutable infrastructure isn&amp;#39;t just about consistency; it&amp;#39;s a must-have for sophisticated, low-downtime deployment strategies that are critical for modern, high-availability applications.&lt;/p&gt;
&lt;p&gt;The benefits of immutability get even bigger when you integrate it into a mature Continuous Integration/Continuous Delivery (CI/CD) pipeline. Many sources emphasize that CI/CD is a vital part of immutable infrastructure. This integration means a change in culture and process: the consistency, quick rollbacks, and better security that immutability offers are fully realized when the entire software delivery process including testing, deployment, and monitoring is automated. Manual processes would cancel out many of these advantages, highlighting why you need to shift your thinking towards automation and that &amp;quot;replace, don&amp;#39;t update&amp;quot; philosophy.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a summary of the main benefits of adopting immutable infrastructure:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;How it&amp;#39;s Achieved&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Better Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cuts down risks by starting from clean, verified states; reduces attack surface; simplifies compliance; helps quick recovery.&lt;/td&gt;
&lt;td&gt;No in-place changes; components cycle frequently; infrastructure defined as auditable code; quick redeployment to known-good states.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;More Consistency &amp;amp; Reliability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ensures identical environments from development to production; gets rid of configuration drift; fewer system failures.&lt;/td&gt;
&lt;td&gt;Version-controlled, predefined configurations; identical copies; replacing systems instead of modifying parts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fewer Deployment Failures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Removes the risk of failed updates from old dependencies or unpredictable configurations.&lt;/td&gt;
&lt;td&gt;Replacing entire systems instead of modifying parts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Easier Troubleshooting &amp;amp; Rollbacks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simpler debugging because instances are identical; quick return to previous states.&lt;/td&gt;
&lt;td&gt;Known, stable system state; predictable upgrades; blue-green deployments.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Improved Scalability &amp;amp; Automation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Makes horizontal scaling fast; works perfectly with IaC.&lt;/td&gt;
&lt;td&gt;Automated, repeatable provisioning; quick deployment of more identical instances; infrastructure as code.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Packer: The Foundation for Immutable Images&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When you&amp;#39;re building immutable infrastructure, creating standardized, pre-configured machine images is a really important first step. HashiCorp Packer is the tool specifically designed for this. It helps you consistently &amp;quot;bake&amp;quot; these images.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What is HashiCorp Packer and How Does it Work?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;HashiCorp Packer is an open-source tool that automates creating identical machine images across different platforms from a single source configuration. These platforms can be anything from cloud providers like AWS (where it makes Amazon Machine Images, or AMIs) to container platforms (Docker images) or virtualization environments (VirtualBox images). People love Packer because it&amp;#39;s lightweight, fast, and can create many images at the same time, which really speeds up the image generation process.&lt;/p&gt;
&lt;p&gt;Packer works based on a template, which you can write in either HCL2 (HashiCorp Configuration Language 2) or JSON format. This template is basically a set of instructions that tell Packer which plugins to use like builders (for example, &lt;code&gt;amazon-ebs&lt;/code&gt;), provisioners, and post-processors how to set them up, and the exact order they should run in. During a typical build, Packer starts a temporary instance from a base image you specify. Then, it connects to this temporary instance to run installation scripts (called &amp;quot;provisioners&amp;quot;) that install software, apply configurations, or do other setup tasks. Once these steps are done, Packer takes a snapshot of this configured instance, registers it as a new machine image (like an AMI), and then shuts down the temporary instance. This makes sure you&amp;#39;re using resources efficiently.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Does Packer Create &amp;quot;Golden AMIs&amp;quot;?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&amp;quot;Golden AMIs&amp;quot; are a cornerstone of immutable infrastructure. These are pre-configured, hardened, and thoroughly tested machine images that act as a reliable starting point for deploying new instances. A Golden AMI usually includes a fully set up operating system, essential software, and specific customizations for particular workloads.&lt;/p&gt;
&lt;p&gt;Packer automates the whole process of building these Golden AMIs. Developers define configurations, often using tools like Ansible playbooks, to precisely customize their images, install needed software, and set up the system to a desired state. This automation makes sure everything is consistent and repeatable across different environments. A really important part of this process is integrating deep security analysis, for instance, by using tools like AWS Inspector V2. This lets you thoroughly scan the AMI for vulnerabilities &lt;em&gt;before&lt;/em&gt; you ever use it in production, proactively cutting down on risks. Once an AMI is successfully created and has passed all necessary security checks, it&amp;#39;s ready to be shared with other accounts or parts of your organization, promoting standardization and secure deployments across the company.&lt;/p&gt;
&lt;p&gt;The idea of &amp;quot;baking in&amp;quot; applications and configurations into an AMI, a term you&amp;#39;ll hear a lot, is more than just convenient; it has big security implications. By putting all dependencies and configurations directly into the image, the resulting AMI becomes a sealed unit. This design naturally reduces the attack surface. For example, you can disable SSH access to instances after they launch, which stops manual, untracked changes. Plus, it makes sure security hardening measures and vulnerability scanning happen &lt;em&gt;before&lt;/em&gt; deployment. This approach shifts security from a reactive runtime monitoring and patching task to a proactive build-time validation and pre-configuration process, making systems more secure right from their beginning.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What Are Packer Templates and How Do They Define Image Builds?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Packer templates are like the blueprints that tell Packer how to build a machine image. These templates specify which builders to use, like &lt;code&gt;amazon-ebs&lt;/code&gt; for creating AWS AMIs, and include details such as the source AMI, the type of instance to use for the build, and how to name the final image.&lt;/p&gt;
&lt;p&gt;A key part of these templates is the &lt;code&gt;provisioner&lt;/code&gt; block. This block lets you define scripts (like shell scripts) or integrate configuration management tools (like Ansible playbooks) that Packer will run on the temporary instance during the build process. These scripts are responsible for installing software, copying files, and configuring the operating system and applications inside the image.&lt;/p&gt;
&lt;p&gt;Historically, Packer templates were written in JSON. But HashiCorp is moving towards HCL2 as the preferred template format, which became official with version 1.7.0. HCL2 is more flexible, modular, and concise than JSON, and because it&amp;#39;s consistent with Terraform&amp;#39;s configuration language, it makes things easier for users already familiar with HashiCorp products.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Do You Handle Versioning for Golden AMIs?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Good versioning is super important for managing Golden AMIs. You should treat them like critical software artifacts in your development process. While Git hashes give you unique IDs, a more human-friendly and operational scheme, like semantic versioning (SemVer), is highly recommended for clarity and easier management by people and QA teams.&lt;/p&gt;
&lt;p&gt;Packer templates make strong versioning possible by letting you include dynamic variables, like &lt;code&gt;BUILD_NUMBER&lt;/code&gt; passed from CI/CD tools, and timestamps directly in the AMI name. This ensures that every new image build has a unique ID and can be traced. For more advanced image management, HashiCorp Cloud Platform (HCP) Packer offers centralized ways to track image metadata and make sure you&amp;#39;re using up-to-date image versions. This is especially valuable for setting up a &amp;quot;30-day repave cycle,&amp;quot; which is a strategy for continuous vulnerability management where instances are regularly rebuilt from the latest, secure images.&lt;/p&gt;
&lt;p&gt;Inside HCP Packer, you can assign images to specific channels (for example, &lt;code&gt;development&lt;/code&gt;, &lt;code&gt;latest&lt;/code&gt;, &lt;code&gt;production&lt;/code&gt;). This channel-based approach lets other tools, like Terraform, &amp;quot;subscribe&amp;quot; to a particular channel, making sure your deployments automatically reference the correct, versioned image ID. This elevates Golden AMIs from just individual images to a strategic asset for your organization. It means image creation becomes a main responsibility for platform engineering teams, who provide standardized, secure, and pre-validated base images to application teams. This centralized way of managing artifacts promotes consistency, cuts down on duplicate work, and enforces security and compliance standards at scale. It really turns image management into a product itself.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Terraform: Orchestrating Immutable Infrastructure&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While Packer sets the stage by creating immutable machine images, HashiCorp Terraform takes on the crucial role of deploying and managing the infrastructure that uses these images. As an Infrastructure as Code (IaC) tool, Terraform is key to making the immutable idea a reality in dynamic cloud environments.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What is HashiCorp Terraform and How Does it Fit into IaC?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;HashiCorp Terraform is an open-source Infrastructure as Code (IaC) tool that lets you define, provision, update, and version cloud and on-premises infrastructure using a declarative configuration language called HashiCorp Configuration Language (HCL). Its main goal is to automate infrastructure management, making sure everything is consistent and significantly cutting down on manual work and potential human errors.&lt;/p&gt;
&lt;p&gt;A key thing that sets Terraform apart is that it&amp;#39;s cloud-agnostic. Unlike IaC tools specific to one cloud, like AWS CloudFormation, Terraform can manage infrastructure across many providers, including AWS, Azure, Google Cloud Platform (GCP), and Kubernetes. This multi-cloud capability gives organizations more flexibility and helps avoid being locked into one vendor. Terraform achieves this broad compatibility by talking to different cloud providers through their APIs, using a system of &amp;quot;providers&amp;quot; or plugins.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Does Terraform Enable Immutable Infrastructure?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Terraform&amp;#39;s declarative configuration language is naturally a great fit for enabling immutable infrastructure. Instead of telling it the exact steps to change an existing instance, Terraform defines the &lt;em&gt;desired final state&lt;/em&gt; of your infrastructure. For immutability, this means configuring Terraform to launch instances from specific, pre-built, and versioned machine images, like the Golden AMIs Packer creates.&lt;/p&gt;
&lt;p&gt;When you need to make changes, Terraform automates setting up &lt;em&gt;new&lt;/em&gt; instances using the updated image version, while at the same time orchestrating the efficient shutdown of the old instances. This process, often called &amp;quot;repaving,&amp;quot; makes sure you stick strictly to the immutable principle of replacement rather than modification. This declarative approach isn&amp;#39;t just a feature; it&amp;#39;s what makes immutable infrastructure possible at scale. By defining the desired state (for example, &amp;quot;this instance should be running version X of the AMI&amp;quot;), Terraform automatically figures out what actions are needed (creating new instances, destroying old ones) to achieve immutability. It hides the procedural steps of replacement, making it practical to manage huge numbers of immutable instances consistently.&lt;/p&gt;
&lt;p&gt;Terraform keeps a really important file called the state file (&lt;code&gt;terraform.tfstate&lt;/code&gt;). This file tracks the real-world infrastructure resources that Terraform manages, acting as a record of their current state. The state file is super helpful for Terraform to understand the deployed infrastructure, spot &amp;quot;drift&amp;quot; (when the actual infrastructure doesn&amp;#39;t match the defined configuration), and apply future changes efficiently. This state file essentially becomes the single &amp;quot;source of truth&amp;quot; for your deployed infrastructure&amp;#39;s desired state. Its security (since it can contain sensitive data and integrity (protected by state locking in remote backends are extremely important. If this file gets compromised or corrupted, it can cause big operational problems, which is why you need strong remote state management, backups, and strict access controls.&lt;/p&gt;
&lt;p&gt;Terraform also supports strategies like rolling updates, which are essential for immutable deployments. In these situations, Terraform creates new instances with the updated configuration, waits for them to be healthy (often by checking health), and then gradually replaces the older instances, minimizing downtime during updates.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What Are Terraform&amp;#39;s Core Capabilities for Infrastructure Management?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Terraform&amp;#39;s wide range of capabilities for infrastructure management can be grouped into three main areas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Manage Infrastructure:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Configuration Language (HCL):&lt;/strong&gt; Terraform uses HCL to describe infrastructure resources across many different providers in a way that&amp;#39;s easy for humans to read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform CLI:&lt;/strong&gt; The Command Line Interface is the main way you interact with Terraform. It lets you initialize configurations (&lt;code&gt;terraform init&lt;/code&gt;), preview changes (&lt;code&gt;terraform plan&lt;/code&gt;), apply modifications (&lt;code&gt;terraform apply&lt;/code&gt;), and destroy resources (&lt;code&gt;terraform destroy&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CDK for Terraform:&lt;/strong&gt; This lets developers define and deploy Terraform configurations using programming languages they already know, offering an alternative to HCL for some situations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provisioners:&lt;/strong&gt; While not as common in a purely immutable setup (where configuration is &amp;quot;baked in&amp;quot;), provisioners can run scripts or commands on a resource &lt;em&gt;after&lt;/em&gt; it&amp;#39;s been created. They&amp;#39;re typically used for bootstrapping or initial setup tasks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaborate:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HCP Terraform (HashiCorp Cloud Platform Terraform):&lt;/strong&gt; This platform is designed to help teams work together on Terraform projects. It offers features like version control integration, shared state management, and governance capabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform Enterprise:&lt;/strong&gt; This is a self-hosted version of HCP Terraform, made for organizations with strict security and compliance needs, giving them more control over their environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote State Management:&lt;/strong&gt; For teams working together, Terraform supports storing state files securely in remote backends (like AWS S3 with DynamoDB for locking, Google Cloud Storage, or Terraform Cloud). This prevents conflicts and makes sure teams are consistent.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Develop and Share:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Providers:&lt;/strong&gt; You can develop custom providers to let Terraform interact with new or proprietary services, extending its reach.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modules:&lt;/strong&gt; Terraform encourages creating reusable configurations through modules. These group related resources, making code easier to maintain, promoting consistency, and allowing for efficient reuse across different projects and environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Registry Publishing:&lt;/strong&gt; Providers and modules can be published to the Terraform Registry, making them publicly available for the wider community or privately within an organization.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;strong&gt;The Immutable Workflow: Packer and Terraform Integration&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The real power of immutable infrastructure comes when you combine Packer and Terraform in an automated pipeline. This pairing creates a smooth workflow, from building images to deploying infrastructure and managing it continuously.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Do Packer and Terraform Work Together for Building and Deploying Versioned Images?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The workflow for immutable infrastructure with Packer and Terraform starts with carefully creating machine images and ends with deploying them efficiently.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Image Building (Packer):&lt;/strong&gt; The first step is to define a Packer template. This template is your blueprint. It specifies the base operating system, includes your application&amp;#39;s source code, any necessary system packages and libraries, and environment variables or runtime configurations. Packer then runs this template to build a versioned machine image, like an Amazon Machine Image (AMI). This process ensures that all required software and configurations are &amp;quot;baked in&amp;quot; to the image, making it self-contained and ready to go.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Image Deployment (Terraform):&lt;/strong&gt; Once Packer successfully builds the versioned image, Terraform takes over. It&amp;#39;s responsible for provisioning your infrastructure. Terraform configurations are set up to reference and deploy new instances using this specific, pre-built, and versioned image. Because everything is pre-configured inside the image, these instances are inherently immutable; they don&amp;#39;t need any SSH tweaks or manual updates after they launch. This strictly follows the &amp;quot;replace, don&amp;#39;t update&amp;quot; rule. The integration point is key: Terraform configurations must always point to the correct, validated, and versioned AMI or image ID that Packer produced, often by subscribing to specific image channels within a registry like HCP Packer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rolling Out Updates:&lt;/strong&gt; When you introduce a new feature, change a dependency, or need a security patch, you repeat the process. You update the Packer template, build a new versioned image (say, &lt;code&gt;v2&lt;/code&gt;), and then use Terraform to deploy new instances that use this &lt;code&gt;v2&lt;/code&gt; image. These new &lt;code&gt;v2&lt;/code&gt; instances are deployed alongside your existing &lt;code&gt;v1&lt;/code&gt; servers, often using strategies like blue-green deployments to minimize downtime. After automated health checks and validation confirm that the &lt;code&gt;v2&lt;/code&gt; instances are stable and working, the &lt;code&gt;v1&lt;/code&gt; servers are gracefully decommissioned. This predictable rollout process means zero configuration drift, no manual intervention, and repeatable deployments, making upgrades and rollbacks straightforward and reliable.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;What Does a Hands-on Workflow Look Like for Provisioning Infrastructure?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;A practical, hands-on workflow for setting up immutable infrastructure with Packer and Terraform usually involves these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; First, make sure you have Packer (version 1.6.6 or later) and Terraform installed on your computer. You&amp;#39;ll also need an AWS account with the right credentials set up.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prepare Packer Configuration:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start by getting an example repository that has the Packer templates and scripts you&amp;#39;ll need. You can clone it like this:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git clone -b packer https://github.com/hashicorp-education/learn-terraform-provisioning
cd learn-terraform-provisioning
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Next, create a local SSH key (for example, tf-packer). This key will be put into the AMI for a dedicated terraform user. This lets you securely access instances launched from the AMI without managing keys directly in AWS.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh-keygen -t rsa -C &amp;quot;your_email@example.com&amp;quot; -f./tf-packer
# When prompted for a passphrase, just press Enter to leave it blank.
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Now, take a look at the shell script (like &lt;code&gt;setup.sh&lt;/code&gt;) that Packer will run when it builds the image. This script usually handles things like installing dependencies, creating users, and downloading application code onto the temporary build instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Navigate to the scripts directory
cd scripts
# Open setup.sh to review its contents
cat setup.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s what a &lt;code&gt;setup.sh&lt;/code&gt; script might look like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;#!/bin/bash
set -x # This helps with debugging by printing commands as they run

# Install necessary dependencies
sudo apt-get update -y
sudo DEBIAN_FRONTEND=noninteractive...[source](https://developer.hashicorp.com/terraform/tutorials/provision/packer)
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; You should never pass scripts you haven&amp;#39;t thoroughly checked into your Packer images.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Now, let&amp;#39;s look at the image.pkr.hcl Packer template. This file defines the image&amp;#39;s parameters, including variables (like region), local values (like a timestamp for unique AMI names), the source block (which specifies the base AMI and instance type), and the build block (which tells Packer to copy files and run the setup script).&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Navigate to the images directory
cd../images
# Open image.pkr.hcl to review its contents
cat image.pkr.hcl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s a simplified &lt;code&gt;image.pkr.hcl&lt;/code&gt; example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;variable &amp;quot;region&amp;quot; {
  type    = string
  default = &amp;quot;us-east-1&amp;quot; # Make sure this matches your AWS region
}

locals {
  timestamp = regex_replace(timestamp(), &amp;quot;&amp;quot;, &amp;quot;&amp;quot;) # Creates a unique timestamp for the AMI name
}

source &amp;quot;amazon-ebs&amp;quot; &amp;quot;example&amp;quot; {
  ami_name      = &amp;quot;learn-terraform-packer-${local.timestamp}&amp;quot;
  instance_type = &amp;quot;t2.micro&amp;quot;
  region        = var.region
  source_ami_filter {
    filters = {
      name                = &amp;quot;ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*&amp;quot;
      root-device-type    = &amp;quot;ebs&amp;quot;
      virtualization-type = &amp;quot;hvm&amp;quot;
    }
    most_recent = true
    owners      = [&amp;quot;099720109477&amp;quot;] # Official Ubuntu AMI owner ID
  }
  ssh_username = &amp;quot;ubuntu&amp;quot;
}

build {
  sources = [&amp;quot;source.amazon-ebs.example&amp;quot;]

  # Copy the SSH public key to the temporary instance
  provisioner &amp;quot;file&amp;quot; {
    source      = &amp;quot;../tf-packer.pub&amp;quot;
    destination = &amp;quot;/tmp/tf-packer.pub&amp;quot;
  }

  # Execute the setup script on the temporary instance
  provisioner &amp;quot;shell&amp;quot; {
    script = &amp;quot;../scripts/setup.sh&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build Packer Image:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First, initialize your Packer configuration:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;packer init image.pkr.hcl
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Then, run the Packer build command, pointing to your image template file:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;packer build -var &amp;quot;region=us-east-1&amp;quot; image.pkr.hcl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Packer will show you the build process, including creating a temporary keypair and security group, launching an AWS instance, stopping it, creating the AMI, and finally shutting down the source instance and cleaning up temporary resources. The last line of the output will give you the AMI ID, which you&amp;#39;ll need for the next step. It&amp;#39;ll look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;==&amp;gt; amazon-ebs.example: AMIs were created:
  us-east-1: ami-0dbaca5d269497603
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deploy with Terraform:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The AMI Packer just created is now available in your AWS account under the EC2 Images section.&lt;/li&gt;
&lt;li&gt;Go to your Terraform configuration directory.&lt;/li&gt;
&lt;li&gt;Open the &lt;code&gt;main.tf&lt;/code&gt; file and find the &lt;code&gt;aws_instance&lt;/code&gt; resource. Update the &lt;code&gt;ami&lt;/code&gt; attribute with the AMI ID you got from your Packer build.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# Navigate to the instances directory
cd../instances
# Open main.tf to update the AMI ID
# Replace &amp;#39;ami-YOUR-AMI-ID&amp;#39; with the actual AMI ID from Packer output
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s how your &lt;code&gt;main.tf&lt;/code&gt; might look after the update:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;#... (other Terraform configuration, like VPC, subnets, security groups)...

resource &amp;quot;aws_instance&amp;quot; &amp;quot;web&amp;quot; {
  ami                    = &amp;quot;ami-0dbaca5d269497603&amp;quot; # Replace with your actual AMI ID
  instance_type          = &amp;quot;t2.micro&amp;quot;
  subnet_id              = aws_subnet.subnet_public.id
  vpc_security_group_ids = [aws_security_group.sg_22_80.id]
  associate_public_ip_address = true
  tags = {
    Name = &amp;quot;Learn-Packer&amp;quot;
  }
}

output &amp;quot;public_ip&amp;quot; {
  value = aws_instance.web.public_ip
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Save your &lt;code&gt;main.tf&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Create a new file called &lt;code&gt;terraform.tfvars&lt;/code&gt; in the same directory and define the &lt;code&gt;region&lt;/code&gt; variable. Make sure this region matches the one you used for Packer, otherwise Terraform won&amp;#39;t be able to find your image.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;region = &amp;quot;us-east-1&amp;quot; # Make sure this matches your Packer region
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Save this file, then initialize and apply your Terraform configuration:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;terraform init &amp;amp;&amp;amp; terraform apply
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Type &lt;code&gt;yes&lt;/code&gt; when Terraform asks you to confirm creating your instance. The final output will be your instance&amp;#39;s public IP address. Your instance now has the SSH key you wanted because it was packaged inside the AMI by Packer. This makes deploying many instances faster and more consistent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verify and Destroy:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Once the instance is deployed, connect to it using SSH. Use the public IP address from the Terraform output and the local SSH key that was pre-packaged in the AMI.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh terraform@$(terraform output -raw public_ip) -i../tf-packer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You now have SSH access to your AWS instance without needing to create an SSH key directly in AWS, which is handy for organizations that manage keypairs externally.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to the Go directory:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cd learn-go-webapp-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Launch the demo web app:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;go run webapp.go
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Open your web browser and go to your instance&amp;#39;s IP address on port &lt;code&gt;8080&lt;/code&gt; to see the deployed application.&lt;/li&gt;
&lt;li&gt;To avoid unnecessary AWS charges, destroy your instance using Terraform when you&amp;#39;re done verifying.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;terraform destroy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Type &lt;code&gt;yes&lt;/code&gt; when prompted to delete your infrastructure. Keep in mind, this command won&amp;#39;t destroy your Packer image. Packer images generally don&amp;#39;t cost money in your AWS account, especially for most basic Linux distributions. But always double-check the cost implications of deploying and keeping your images.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;How Does CI/CD Pipeline Integration Make Immutable Deployments Better?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Bringing Packer and Terraform into a Continuous Integration/Continuous Delivery (CI/CD) pipeline is a huge step forward in automating infrastructure management. This integration goes beyond just automating application deployments; it automates the &lt;em&gt;entire lifecycle&lt;/em&gt; of the infrastructure itself from image creation to provisioning, updating, and decommissioning. This complete automation makes sure your infrastructure is treated as a disposable, versioned artifact, allowing for quick recovery, consistent environments, and continuous security.&lt;/p&gt;
&lt;p&gt;CI/CD pipelines, using tools like GitHub Actions, Jenkins, GitLab CI, or AWS CodePipeline, automate the whole process from code commit to infrastructure deployment. This automation is vital for keeping your immutable infrastructure strategy intact and efficient.&lt;/p&gt;
&lt;p&gt;A key benefit of this integration is much better &lt;strong&gt;vulnerability management&lt;/strong&gt;. You can set up a &amp;quot;30-day repave cycle,&amp;quot; where instances are regularly recreated from the latest, secure images. This significantly cuts down on vulnerability risks. The CI/CD pipeline automates rebuilding Packer images whenever vulnerabilities are fixed, making sure your deployed systems are always running patched and secure images. This &amp;quot;repaving&amp;quot; strategy turns security from a periodic audit and patching task into an inherent, automated part of the deployment process, drastically reducing how long you&amp;#39;re exposed to vulnerabilities. Compliance, too, becomes a natural part of your image and infrastructure definitions.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s more, CI/CD integration enables proactive &lt;strong&gt;drift detection and remediation&lt;/strong&gt;. HashiCorp Cloud Platform (HCP) Terraform can spot when your deployed infrastructure&amp;#39;s state doesn&amp;#39;t match its desired configuration, especially when a new image version is assigned to a production channel in HCP Packer. When this drift is detected, it automatically triggers &lt;code&gt;terraform apply&lt;/code&gt; operations in the relevant workspaces, leading to the redeployment of infrastructure with the new, updated images.&lt;/p&gt;
&lt;p&gt;The pipeline also includes &lt;strong&gt;compliance and security scans&lt;/strong&gt;. You can add stages to perform checks, like using AWS Inspector V2 for AMIs, making sure that both your infrastructure and deployed applications meet your organization&amp;#39;s compliance requirements and security standards. Any non-compliant elements can trigger alerts or even stop further pipeline stages, preventing the deployment of potentially risky configurations.&lt;/p&gt;
&lt;p&gt;Finally, &lt;strong&gt;version control&lt;/strong&gt; is fundamental to this integrated approach. Both Packer templates and Terraform configurations are managed under version control systems. This ensures complete traceability and reproducibility throughout the pipeline. It makes auditing changes easy, simplifies rollbacks, and fosters a collaborative environment where all infrastructure definitions are treated as code. Integrating these tools within a CI/CD pipeline means you&amp;#39;re moving from just &amp;quot;deployment automation&amp;quot; to full &amp;quot;infrastructure lifecycle automation,&amp;quot; where infrastructure is a first-class citizen in your automated pipeline.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Addressing Challenges and Best Practices&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While immutable infrastructure offers some great advantages, adopting it isn&amp;#39;t without its hurdles. Understanding these challenges and putting the right best practices in place is key for a smooth transition and ongoing success.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What Are the Common Challenges of Adopting Immutable Infrastructure?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Organizations often run into a few common problems when they switch to immutable infrastructure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;More Resource Use and Higher Storage Needs:&lt;/strong&gt; A core idea of immutability is replacing instances for every change. This can mean you use more computing resources as new instances spin up alongside existing ones during updates. Plus, keeping multiple old versions of images for rollbacks can significantly increase your storage needs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex Initial Setup and Learning Curve:&lt;/strong&gt; Building the basic parts for immutable infrastructure, especially setting up strong CI/CD pipelines and image creation processes, takes a lot of effort upfront. Teams also have to deal with learning new tools like Packer, Docker, and Kubernetes. More importantly, they need to fundamentally change their mindset from &amp;quot;update in place&amp;quot; to &amp;quot;replace, don&amp;#39;t update&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Different Debugging and Troubleshooting:&lt;/strong&gt; Finding and fixing problems in immutable systems can be harder than in mutable environments. You&amp;#39;re not allowed to directly change running systems, so traditional debugging methods like logging into a server and making live changes don&amp;#39;t apply. Instead, troubleshooting often means recreating the problematic image or container in a clean, isolated environment to figure out the issue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limited Flexibility:&lt;/strong&gt; The strict rule of immutability means that even small configuration changes or updates require creating and deploying a completely new version of the infrastructure. If this isn&amp;#39;t fully automated, the process can feel clunky and time-consuming.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility Issues with Older Systems:&lt;/strong&gt; Older applications and systems that weren&amp;#39;t built with immutable principles in mind might cause big compatibility problems. These legacy applications often rely on in-place updates or keep their state directly on the server, making a full reinstallation with every change difficult or impractical.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;How Does Immutable Infrastructure Handle Stateful Applications?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Immutable infrastructure generally works better with stateless applications, which don&amp;#39;t keep data between sessions or transactions. Stateful applications like databases, file systems, or services that rely on sessions naturally hold onto persistent data. This makes tearing down and replacing infrastructure components tricky because of the risk of data loss or complicated data migration challenges.&lt;/p&gt;
&lt;p&gt;The inherent conflict between immutability and stateful applications shows that immutable infrastructure isn&amp;#39;t a one-size-fits-all solution for &lt;em&gt;all&lt;/em&gt; infrastructure components. Managing stateful applications within an immutable setup needs careful architectural planning to separate state management from the immutable parts. This often means putting your data storage somewhere else, like in dedicated, often managed, services such as cloud databases (e.g., AWS RDS), cloud storage buckets (e.g., S3), or using persistent volumes in container orchestration platforms like Kubernetes StatefulSets.&lt;/p&gt;
&lt;p&gt;Good practices for managing stateful applications in a DevOps context, even if you&amp;#39;re using immutable principles for other layers, include: separating data and application logic, considering containerized databases when it makes sense, setting up strong backup and recovery systems, adopting disciplined database migration practices, and creating comprehensive disaster recovery and failover plans.&lt;/p&gt;
&lt;p&gt;A common and effective strategy is to use a &lt;strong&gt;hybrid approach&lt;/strong&gt;. This means using immutable infrastructure for stateless services (like web servers, microservices, or application servers) where consistency and repeatability are most important, while keeping mutable infrastructure or using managed services for stateful components or older systems where preserving data and flexibility are more critical. Terraform&amp;#39;s flexibility as an IaC tool lets organizations manage both mutable and immutable models at the same time within the same configuration. This gives you the adaptability you need to implement such a hybrid approach effectively. This architectural judgment, rather than just applying the immutable idea everywhere, is often key to success.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What Are the Best Practices for Terraform Workflows?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To get the most out of immutable infrastructure and handle its challenges, it&amp;#39;s essential to follow established best practices for Terraform workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Version Control:&lt;/strong&gt; Treat all your Infrastructure as Code (IaC) configurations, including Terraform code and Packer templates, with the same care as application code. Store them in a version control system (like Git) to track changes, allow collaboration, and make rollbacks easier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote State Management:&lt;/strong&gt; For team collaboration and better security, always use a remote shared state location (like AWS S3 with DynamoDB for locking, or HashiCorp Terraform Cloud) instead of local state files. It&amp;#39;s crucial to treat the Terraform state as immutable and strictly avoid changing it manually. Set up strong backup systems and enable versioning for the state file to ensure quick recovery if something goes wrong.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Module Utilization:&lt;/strong&gt; Use existing shared and community modules from the Terraform Registry to avoid reinventing the wheel and benefit from community expertise. If you have specific needs, build your own reusable modules, making sure their inputs and outputs are clearly defined to promote consistency and reuse across different projects and environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rigorous Testing:&lt;/strong&gt; Put a comprehensive testing strategy in place for your Terraform code. This includes using &lt;code&gt;terraform plan&lt;/code&gt; for a quick check of changes, doing static analysis with linters (like &lt;code&gt;tflint&lt;/code&gt;, &lt;code&gt;checkov&lt;/code&gt;) to catch errors without applying changes, running unit tests for different parts of your system, and setting up integration tests in isolated sandbox environments before deploying to production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI/CD Integration:&lt;/strong&gt; Automate running &lt;code&gt;terraform init&lt;/code&gt;, &lt;code&gt;plan&lt;/code&gt;, and &lt;code&gt;apply&lt;/code&gt; commands within your CI/CD pipelines. This ensures consistent, automated, and error-free deployments, which is fundamental to the immutable idea.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistent Naming and Tagging:&lt;/strong&gt; Set up and strictly follow consistent naming conventions for all Terraform resources and implement a strong tagging strategy. Tags are incredibly useful for identifying resources, allocating costs, and controlling access.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Policy as Code:&lt;/strong&gt; Introduce policy-as-code frameworks (like HashiCorp Sentinel) to define and automatically enforce your organization&amp;#39;s rules for security, compliance, and acceptable configurations at scale. This proactively stops non-compliant deployments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid Hardcoding:&lt;/strong&gt; Try to avoid hardcoding values directly in your Terraform configurations as much as possible. Instead, use variables and data sources to get values dynamically, making your configurations more flexible and reusable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plan for Rollbacks:&lt;/strong&gt; Always have a well-defined and tested rollback strategy. The immutable nature of the infrastructure naturally simplifies rollbacks, as going back to a previous state just means deploying an earlier, validated image version.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;How Do You Securely Manage Secrets in Packer and Terraform?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Securely managing sensitive data, like credentials and API keys, is extremely important in any infrastructure, especially in an immutable setup.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Never Hardcode Secrets:&lt;/strong&gt; A critical security best practice is to never put secrets directly into Packer templates, Terraform configurations, or commit them to version control systems. This is very insecure and creates big vulnerabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Secret Management Tools:&lt;/strong&gt; The recommended way is to get credentials and sensitive data dynamically from dedicated, secure secret management solutions during the build or deployment process. Tools like HashiCorp Vault or cloud-native services such as AWS Secrets Manager are designed for this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Packer Integration with Vault:&lt;/strong&gt; Packer can directly connect with HashiCorp Vault to pull dynamic secrets during the image building process. The &lt;code&gt;vault&lt;/code&gt; function within Packer templates lets you read secrets from a Vault KV store and use them as user variables, making sure sensitive information isn&amp;#39;t embedded in the image definition itself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform Integration with Vault:&lt;/strong&gt; Similarly, the Terraform Vault provider lets Terraform connect to a Vault cluster, read dynamic secrets, and securely provide them to user scripts or resources during infrastructure provisioning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environment Variables (with caution):&lt;/strong&gt; While not ideal for long-term storage or highly sensitive data, environment variables (like &lt;code&gt;TF_VAR&lt;/code&gt; for Terraform) can be used for sensitive variables, especially when marked with &lt;code&gt;sensitive = true&lt;/code&gt; to prevent them from showing up in logs. But use this method carefully.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IAM Roles for Permissions:&lt;/strong&gt; Using Identity and Access Management (IAM) roles is a strong security practice. Configure Packer and Terraform to assume specific IAM roles that grant only the necessary permissions to interact with cloud resources, instead of putting static access keys directly in your code. This follows the principle of least privilege and makes overall security better.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Successfully adopting immutable infrastructure needs a significant investment from your organization that goes beyond just tools. It requires a &amp;quot;learning curve and cultural shift&amp;quot;. The initial setup complexity and the different ways of debugging can become huge roadblocks if you don&amp;#39;t address them proactively. This highlights the need for substantial investment in training, fostering a culture of automation, promoting collaboration, and committing to continuous improvement. Without this cultural buy-in and investment in people and processes, organizations might struggle to fully realize the benefits of immutability, no matter how good the tools are. It&amp;#39;s about fundamentally changing &lt;em&gt;how&lt;/em&gt; teams work, not just &lt;em&gt;what&lt;/em&gt; tools they use.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a table summarizing the challenges and how to handle them:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Challenge&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;How to Handle It&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;More Resource Use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;New instances for every change mean more computing power used.&lt;/td&gt;
&lt;td&gt;Optimize image size; use efficient resource tagging to track costs; use auto-scaling groups to manage instance lifecycles.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Higher Storage Needs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Keeping many image versions for rollbacks uses more storage.&lt;/td&gt;
&lt;td&gt;Implement image lifecycle policies; regularly clean up old, unused AMIs; use artifact registries with versioning and revocation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compatibility with Older/Stateful Apps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not ideal for apps needing in-place updates or persistent data.&lt;/td&gt;
&lt;td&gt;Use a hybrid approach (immutable for stateless, mutable/managed for stateful); put data storage somewhere else (databases, cloud storage); use Kubernetes StatefulSets.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complex Initial Setup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A lot of upfront work to build CI/CD pipelines and image creation processes.&lt;/td&gt;
&lt;td&gt;Start small and build up; use existing community modules and templates; invest in skilled people or get outside help.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve/Cultural Shift&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires learning new tools and a &amp;quot;replace, don&amp;#39;t update&amp;quot; mindset.&lt;/td&gt;
&lt;td&gt;Provide thorough training; encourage a culture of automation and continuous learning; promote teamwork.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Debugging Differences&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can&amp;#39;t directly change running systems, making traditional debugging harder.&lt;/td&gt;
&lt;td&gt;Recreate problematic images in clean environments; improve logging and monitoring; use build-time validation and testing.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Common Questions about Immutable Infrastructure with Packer and Terraform&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;As organizations look into and adopt immutable infrastructure, a few common questions pop up about how it works in practice and how it interacts with tools like Packer and Terraform.&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What is configuration drift and how does immutable infrastructure prevent it?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Configuration drift is when the actual state of your infrastructure components slowly moves away from their intended or defined setup over time. This often happens because of manual changes, quick fixes, or inconsistencies introduced outside of automated processes. This drift leads to unpredictable behavior, makes troubleshooting harder, and can even introduce security vulnerabilities.&lt;/p&gt;
&lt;p&gt;Immutable infrastructure naturally prevents configuration drift by design. The main rule is that instances are never changed in place. Instead, any change, no matter how small, means you create a new, identical instance from a version-controlled, predefined image. This makes sure every deployment starts fresh with a clean slate, and your infrastructure always matches the desired configuration, completely getting rid of differences across environments.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can I use immutable infrastructure for legacy systems?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;While immutable infrastructure is super beneficial for cloud-native applications, containerized workloads, and microservices architectures, it can cause compatibility problems for older systems. Many older applications weren&amp;#39;t built expecting frequent, complete replacements of their underlying infrastructure, or they might rely on in-place updates and local state. Trying to force an old system into a purely immutable model might need big changes, which can be expensive and complicated.&lt;/p&gt;
&lt;p&gt;A practical and often recommended approach is to use a hybrid model. This means keeping mutable infrastructure for older systems or stateful components where it makes more sense, while at the same time using immutable practices for newer, stateless services. Terraform, with its ability to manage both mutable and immutable resources, gives you the flexibility to orchestrate such a hybrid environment effectively.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do rolling updates work with Terraform in an immutable setup?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Rolling updates are a deployment strategy designed to update infrastructure bit by bit, minimizing downtime and making sure your application stays available continuously. In an immutable infrastructure setup, this process is very smooth. Terraform orchestrates creating new instances that are provisioned from the updated, versioned machine image. As these new instances become healthy (often checked through integrated health checks), Terraform gradually replaces the older instances.&lt;/p&gt;
&lt;p&gt;This phased replacement usually happens by using Terraform&amp;#39;s meta-arguments like &lt;code&gt;count&lt;/code&gt; or &lt;code&gt;for_each&lt;/code&gt; within resource definitions. These let you manage multiple instances and carefully control when new ones are created and old ones are destroyed in a controlled, phased way.&lt;/p&gt;
&lt;p&gt;A specific and very effective strategy that fits perfectly with immutability and rolling updates is &lt;strong&gt;Blue/Green deployments&lt;/strong&gt;. In this model, you deploy a completely new &amp;quot;green&amp;quot; environment, running the updated application version, right alongside the existing &amp;quot;blue&amp;quot; production environment. Once the &amp;quot;green&amp;quot; environment is thoroughly tested and validated, traffic is seamlessly switched from &amp;quot;blue&amp;quot; to &amp;quot;green.&amp;quot; If any problems come up, traffic can be instantly sent back to the &amp;quot;blue&amp;quot; environment, giving you a quick rollback option. Only after successful validation and traffic switchover do you decommission the old &amp;quot;blue&amp;quot; environment. The ability to spin up a completely new, identical environment and then switch traffic is fundamentally possible because the underlying components are immutable. This shows how immutable infrastructure is a must-have for sophisticated, low-downtime deployment strategies.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What is the role of the Terraform state file in immutable infrastructure?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Terraform state file (&lt;code&gt;terraform.tfstate&lt;/code&gt;) is a critical component that keeps track of the real-world infrastructure managed by Terraform. It acts as a permanent record of the resources Terraform created and manages, helping the tool understand the current state of the infrastructure, detect any differences (drift) from the defined configuration, and apply future changes efficiently.&lt;/p&gt;
&lt;p&gt;In an immutable infrastructure context, the state file records which specific versioned AMI or image is deployed to which instance. This precise tracking is incredibly valuable for keeping things consistent, allowing for accurate auditing, and making straightforward rollbacks to previous known-good states possible. If you need to roll back, Terraform can look at the state file to find the previously deployed image version and orchestrate its redeployment.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does immutable infrastructure simplify disaster recovery?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Immutable infrastructure makes disaster recovery processes much simpler by fundamentally changing how you restore systems. Since every deployed instance is identical and built from a version-controlled, unchanging image, recovering from a failure or security incident becomes remarkably straightforward.&lt;/p&gt;
&lt;p&gt;Instead of needing to diagnose, repair, or patch compromised components on a live system, administrators can simply roll back to a previous known-good state by redeploying an older, validated image version. This gets rid of the time-consuming and complex process of debugging potentially &amp;quot;snowflake&amp;quot; servers. The ability to quickly provision a clean, identical environment from a trusted image drastically reduces recovery time and minimizes downtime, making your overall system more resilient.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Why is secure secret management important in immutable infrastructure?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Even with an immutable infrastructure model, your applications and the underlying infrastructure still need access to sensitive credentials, like database passwords, API keys, and private keys, both when you&amp;#39;re building images and when instances are running.&lt;/p&gt;
&lt;p&gt;Putting these secrets directly into Packer templates, Terraform configurations, or committing them to version control systems is a serious security vulnerability. Such practices can lead to unauthorized access, data breaches, and compromise your entire infrastructure. So, secure secret management tools, like HashiCorp Vault or cloud-native secrets managers, are absolutely crucial. These tools make sure secrets are retrieved dynamically and securely injected into the build or deployment process, minimizing the attack surface and helping you stay compliant with security policies. This approach ensures that sensitive data is never hardcoded, is rotated regularly, and access is tightly controlled, fitting right in with the overall security of an immutable environment.&lt;/p&gt;
&lt;p&gt;Talking about these common questions really reinforces that Packer and Terraform aren&amp;#39;t just standalone tools. They&amp;#39;re part of a bigger DevOps ecosystem. Questions about configuration drift, older systems, rolling updates, state files, and secrets management all point to a complete approach where the idea of immutability is supported by specific tools (Packer, Terraform, Vault) and processes (CI/CD, versioning, testing). This shows that successfully adopting immutable infrastructure means understanding how all these pieces connect and how they work together to make things reliable, secure, and agile, rather than just focusing on what each tool does on its own.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;Conclusion: The Future of Infrastructure Management&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Adopting immutable infrastructure, carefully put into practice with tools like HashiCorp Packer and Terraform, is a huge and transformative change in how we design, deploy, and manage modern IT systems. This approach moves past the traditional, changeable way of making in-place modifications and instead embraces a &amp;quot;replace, don&amp;#39;t update&amp;quot; philosophy. This fundamentally changes how we operate.&lt;/p&gt;
&lt;p&gt;At its heart, immutable infrastructure means that once a server, VM, or container is deployed, it stays exactly as it is. If you need any updates or changes, you do them by setting up completely new, updated instances and gracefully shutting down the old ones. Packer is the foundational tool in this system. It helps you automatically create &amp;quot;Golden AMIs&amp;quot; standardized, pre-configured, and thoroughly tested machine images. These images, which are versioned and often scanned for security during their build process, become the unchangeable building blocks of your infrastructure. To complement this, Terraform acts as the orchestrator. It uses its Infrastructure as Code capabilities to declaratively set up and manage your infrastructure using these immutable images. Terraform automates deploying new instances from the latest Golden AMIs and handles the process of replacing older versions, ensuring consistency and efficiency.&lt;/p&gt;
&lt;p&gt;The benefits you get from this approach are significant and far-reaching. Organizations see much better security because every deployment starts from a clean, verified state, which cuts down on attack surfaces and stops vulnerabilities from sticking around. Consistency and reliability improve dramatically by getting rid of configuration drift and making sure environments are identical across development, testing, and production. Operations become simpler thanks to extensive automation, leading to fewer deployment failures and more predictable release cycles. Plus, troubleshooting is easier, and rollbacks are incredibly straightforward often as simple as redeploying a previous, known-good image version. This foundation also naturally supports advanced deployment strategies like blue/green deployments and makes horizontal scaling easier.&lt;/p&gt;
&lt;p&gt;While switching to immutable infrastructure has its challenges like more resource consumption, higher storage needs, and an initial learning curve you can effectively manage these. Careful planning, strategically separating stateful applications from immutable components (often by putting storage somewhere else or using managed services), and sticking to strong best practices for Terraform workflows (including remote state management, using modules, thorough testing, and secure secret management with tools like HashiCorp Vault) are crucial for success.&lt;/p&gt;
&lt;p&gt;The seamless integration of Packer and Terraform within a strong CI/CD pipeline is the cornerstone of a successful immutable infrastructure strategy. This integration allows for automated &amp;quot;repaving&amp;quot; cycles, ensuring continuous vulnerability management and predictable deployments. It means you&amp;#39;re moving from just deployment automation to complete infrastructure lifecycle automation, where security and compliance are built into the process rather than being reactive add-ons.&lt;/p&gt;
&lt;p&gt;Essentially, immutable infrastructure, powered by Packer and Terraform, isn&amp;#39;t just a passing trend; it&amp;#39;s a fundamental change in how we manage infrastructure. It&amp;#39;s an essential approach for organizations embracing cloud-native development, microservices architectures, and fast-paced DevOps practices. By treating infrastructure as disposable, versioned artifacts, organizations can build systems that are naturally more resilient, secure, and scalable, setting themselves up for ongoing success in the ever-changing digital world.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Provision infrastructure with Packer | Terraform | HashiCorp Developer, accessed on June 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/terraform/tutorials/provision/packer&quot;&gt;https://developer.hashicorp.com/terraform/tutorials/provision/packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform overview | Terraform | HashiCorp Developer, accessed on June 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/terraform/docs&quot;&gt;https://developer.hashicorp.com/terraform/docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Documentation | Packer | HashiCorp Developer, accessed on June 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/packer/docs&quot;&gt;https://developer.hashicorp.com/packer/docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Templates | Packer | HashiCorp Developer, accessed on June 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/packer/docs/templates&quot;&gt;https://developer.hashicorp.com/packer/docs/templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vault function reference | Packer - HashiCorp Developer, accessed on June 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/contextual/vault&quot;&gt;https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/contextual/vault&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Vulnerability and patch management of infrastructure images with HCP, accessed on June 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/validated-patterns/terraform/vulnerability-and-patch-management&quot;&gt;https://developer.hashicorp.com/validated-patterns/terraform/vulnerability-and-patch-management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Is Immutable Infrastructure? Benefits and Implementation - Legit Security, accessed on June 6, 2025, &lt;a href=&quot;https://www.legitsecurity.com/aspm-knowledge-base/what-is-immutable-infrastructure&quot;&gt;https://www.legitsecurity.com/aspm-knowledge-base/what-is-immutable-infrastructure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Immutable Infrastructure: Enhancing Reliability and Consistency ..., accessed on June 6, 2025, &lt;a href=&quot;https://infiniticube.com/blog/immutable-infrastructure-enhancing-reliability-and-consistency/&quot;&gt;https://infiniticube.com/blog/immutable-infrastructure-enhancing-reliability-and-consistency/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;20 Terraform Best Practices to Improve your TF workflow - Spacelift, accessed on June 6, 2025, &lt;a href=&quot;https://spacelift.io/blog/terraform-best-practices&quot;&gt;https://spacelift.io/blog/terraform-best-practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Managing Stateful Applications in DevOps: Best Practices - Aegis Softtech, accessed on June 6, 2025, &lt;a href=&quot;https://www.aegissofttech.com/insights/stateful-applications-in-devops/&quot;&gt;https://www.aegissofttech.com/insights/stateful-applications-in-devops/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Infrastructure as Code</category><category>Cloud Computing</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0096-immutable-infrastructure-packer-terraform-guide/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Unlocking Scalability: A Comprehensive Guide to Modular Terraform for IaC</title><link>https://mkabumattar.com/blog/post/modular-terraform-scalable-iac-guide/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/modular-terraform-scalable-iac-guide/</guid><description>Master scalable Infrastructure as Code with modular Terraform. Learn best practices for design, versioning, testing, and state management to build robust, consistent, and automated cloud infrastructure.</description><pubDate>Sat, 14 Feb 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today, businesses need infrastructure that&amp;#39;s not just strong, but also super flexible and able to grow fast. Trying to manage all that by hand just won&amp;#39;t cut it anymore. That&amp;#39;s why Infrastructure as Code, or IaC, has become such a game-changer. It&amp;#39;s totally changed how we build and manage our digital foundations.&lt;/p&gt;
&lt;p&gt;IaC means you define and manage your infrastructure using code, bringing all those great software development practices into how you run things. And when it comes to IaC tools, Terraform is a real standout. It lets you define and set up infrastructure across all sorts of cloud providers with surprising ease. Now, IaC and Terraform are powerful on their own, but if you really want to make things scalable and easy to manage in big, complex setups, there&amp;#39;s one key idea: modular design. This guide will show you how modular Terraform helps you build infrastructure that&amp;#39;s not just automated, but truly scalable, consistent, and simple to keep up with.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What is Infrastructure as Code (IaC) and Why is it Indispensable?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Infrastructure as Code (IaC) is a huge shift in how we handle digital infrastructure. It&amp;#39;s all about managing and setting up your infrastructure using configuration files that computers can read, instead of doing everything by hand, which often leads to mistakes. Basically, IaC treats infrastructure parts like networks, virtual machines, and databases with the same care and methods you&amp;#39;d use for regular software code. This way, you automate setting up, deploying, configuring, and managing your infrastructure, from physical hardware to virtual machines and cloud stuff.&lt;/p&gt;
&lt;p&gt;The main ideas behind IaC are what make it so effective. Automation is a huge one; it gets rid of all those manual steps in setting up, deploying, configuring, and managing your infrastructure. This automation is key for agile development, continuous integration/continuous delivery (CI/CD), and modern DevOps ways of working. It&amp;#39;s not just about being fast, either. This automation directly makes businesses more agile. When you can set up and manage infrastructure quickly, you can develop, test, and deploy applications much faster. This speeds up the whole software development process, letting companies react to market changes, release new features, and grow operations way quicker than old manual methods ever would. That really helps with staying competitive and making money.&lt;/p&gt;
&lt;p&gt;Consistency and repeatability are super important too. Because you&amp;#39;re using code, IaC really cuts down on configuration errors and gets rid of those inconsistencies that pop up when different people are doing manual setups. This means if you apply the same configuration over and over, you&amp;#39;ll always get the exact same result, no matter what the system looked like before that&amp;#39;s called idempotency. This helps different teams set up consistent and repeatable ways to manage infrastructure. Plus, IaC encourages immutability. That means infrastructure is set up as resources that can&amp;#39;t be changed. If you need a change, you create brand new infrastructure and swap it out, instead of tweaking the old stuff. This makes it easier to roll back quickly and keeps your environments really consistent. Finally, just like any other code, IaC configurations work great with version control. This gives you full history of changes and helps keep track of who did what to the infrastructure.&lt;/p&gt;
&lt;p&gt;The advantages you get from IaC are huge and really make a difference. Speed is a big one; setting up infrastructure with code scripts is way faster than doing it by hand, so you get resources ready quickly. Accuracy is another major plus. Code-driven setups drastically cut down on human errors and inconsistencies. Version control also boosts accountability and transparency, giving you a full history of changes, which is great for audits and compliance. IaC also makes things more efficient, making software development smoother, using resources better, and letting IT teams focus on more important work. These efficiencies often mean big cost savings, because automation minimizes mistakes and gets rid of time-consuming manual work, helping you save on hardware, staff, and storage. And IaC naturally supports scalability, letting companies easily grow their infrastructure without spending too much, since automation reduces those misconfigurations and manual tasks that usually slow things down.&lt;/p&gt;
&lt;p&gt;Now, people often praise IaC for cutting down on security risks by reducing human error which, by the way, causes most cyberattacks. But its ideas of consistency and reproducibility actually help reduce risks across &lt;em&gt;all&lt;/em&gt; your operations, not just security. Consistent, repeatable processes mean less configuration drift and fewer surprises in your CI/CD pipelines and testing. This consistency helps with all sorts of operational risks, like unexpected downtime, slow performance, and tricky debugging issues. It makes sure your environments act predictably, which is super important for overall system reliability and smooth disaster recovery. So, it&amp;#39;s not just about security; it&amp;#39;s about making your whole infrastructure stable and resilient.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How Does Terraform Empower Your IaC Strategy?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Terraform has really become a core part of the Infrastructure as Code world. It&amp;#39;s an open-source IaC tool from HashiCorp, written in Golang. Most folks see it as the go-to standard for managing cloud resources. Terraform lets engineers define their infrastructure in code, then set up, manage, and deploy those resources across different cloud providers like AWS, Azure, and Google Cloud (GCP) all with one tool. And it&amp;#39;s not just for cloud environments; Terraform can also automate things with Kubernetes, Helm, and even custom providers, showing just how flexible it is.&lt;/p&gt;
&lt;p&gt;One key thing about Terraform is that it uses a declarative programming language called HashiCorp Configuration Language, or HCL. With declarative syntax, you tell Terraform &lt;em&gt;what&lt;/em&gt; you want your infrastructure to look like in the end, and it smartly figures out the best way to get and keep it that way. This is pretty different from imperative ways of working, where you have to spell out every single step and the order it needs to happen in. HCL is a Domain Specific Language (DSL), which means it&amp;#39;s designed for this specific job. That makes it easier and faster for developers to get productive with just a little bit of syntax learning, because it hides away the complicated stuff you&amp;#39;d find in general programming languages.&lt;/p&gt;
&lt;p&gt;Terraform&amp;#39;s declarative style, along with how simple HCL is, makes it much easier to manage complex, spread-out systems at scale. Since you&amp;#39;re focusing on &lt;em&gt;what&lt;/em&gt; your infrastructure should be, not &lt;em&gt;how&lt;/em&gt; to build it step-by-step, engineers can let Terraform handle all the tricky dependency mapping and execution order. This really lightens the load on engineers, letting them focus on designing the architecture instead of tiny operational details. This simplification is vital for dealing with the natural complexity of big cloud environments, where trying to manage dependencies by hand would lead to tons of errors and take forever. The outcome? Faster development cycles and fewer deployment failures caused by wrong sequencing.&lt;/p&gt;
&lt;p&gt;Terraform works thanks to a few key parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Providers&lt;/strong&gt; are like plugins that let Terraform talk to specific infrastructure resources, like AWS or Azure Resource Manager. They&amp;#39;re the bridge, turning your Terraform setups into the right API calls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resources&lt;/strong&gt; are the actual infrastructure pieces Terraform manages, things like virtual machines, networks, and databases. They&amp;#39;re the basic building blocks of any Terraform setup.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Variables&lt;/strong&gt; work a lot like variables in regular programming. You use them to organize your code, make it easier to change how things behave, and help with reuse. Variables can be different types, like text, numbers, true/false, lists, and maps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outputs&lt;/strong&gt; show you values from data sources, resources, or variables after Terraform runs, or they can expose details from a module for use somewhere else.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Sources&lt;/strong&gt; pull in information from outside places, like existing infrastructure. This lets you use that info in new resources or local variables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You really can&amp;#39;t overstate how important Terraform&amp;#39;s state management is. Terraform is a &lt;strong&gt;stateful&lt;/strong&gt; tool, meaning it carefully keeps track of your infrastructure&amp;#39;s current status by comparing your IaC setup with a state file it creates after every run. This file, usually called &lt;code&gt;terraform.tfstate&lt;/code&gt;, is a detailed JSON structure that lists all the resources it manages and any changes it plans to make. While new users might start with a local state file that&amp;#39;s a big no-no for teams because it can easily lead to conflicts and configuration drift. For bigger operations, especially with lots of engineers, the state is usually split into several files and stored remotely in services like AWS S3 or Terraform Cloud. Remote state is key because it lets multiple people access it, locks the state to stop simultaneous changes, and makes things more secure with encryption.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s something really important to grasp: even though state management is a core feature, it can also be a major source of complexity and risk if you don&amp;#39;t handle it carefully, especially when teams are working together. The state file, while vital for Terraform&amp;#39;s declarative way of working, is your single source of truth. If this file gets messed up, becomes old, or isn&amp;#39;t managed well say, because someone made manual changes outside of Terraform (what we call &amp;quot;ClickOps&amp;quot;) can cause big infrastructure problems, like accidentally deleting resources or widespread misconfigurations. This means state management isn&amp;#39;t just a technical detail; it&amp;#39;s a critical operational and security issue. It really highlights that even with all the benefits of automation, you still need strong human processes and dedicated tools around that state file to prevent major outages or data breaches.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why Modular Design is the Cornerstone of Scalable Terraform?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Terraform modules are absolutely essential for building Infrastructure as Code that you can scale and easily maintain. Think of them as reusable, self-contained bundles of Terraform setups. These modules wrap up specific resources, like virtual machines, networks, and databases, putting all the related resources, variables, and outputs into one neat package. It&amp;#39;s worth remembering that Terraform sees every configuration as a module; the folder where you run &lt;code&gt;terraform plan&lt;/code&gt; or &lt;code&gt;apply&lt;/code&gt; is what it calls the &amp;quot;root module&amp;quot;.&lt;/p&gt;
&lt;p&gt;Modular design offers many advantages, as you can see in the table below. It really helps with scalability and other important IaC benefits:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Benefit&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reusability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Infrastructure components can be defined once and reused across multiple projects and environments, eliminating code duplication and simplifying the codebase.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consistency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Uniform configurations and reliability are ensured across all deployments and environments, minimizing errors and preventing configuration drift.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Functionality is encapsulated, centralizing updates to shared components and simplifying troubleshooting efforts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Efficient infrastructure growth is enabled by effectively managing complexity, reducing misconfigurations, and accelerating deployments at scale.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Collaboration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Teamwork is facilitated as members can easily share, maintain, and contribute to common infrastructure components, streamlining DevOps practices.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Abstraction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complex configurations are simplified by hiding internal implementation details, allowing users to focus solely on inputs and outputs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reduced Sprawl&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The proliferation of redundant configurations is combated by enforcing the &amp;quot;Don&amp;#39;t Repeat Yourself&amp;quot; (DRY) principle, leading to a more concise codebase.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Modularity directly tackles the problem of configuration sprawl and makes things much more consistent across different environments. By wrapping up common infrastructure patterns into reusable blocks, modules mean you don&amp;#39;t have to write the same setup over and over again for different projects and environments. This stops one huge configuration file from getting messy and hard to handle as your infrastructure grows. When you need to update something, you only have to change it in that one central module. That really cuts down on the work and the chance of errors that come with making changes everywhere.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s more, modules make sure your configurations are standardized, guaranteeing everything looks the same across all deployments, no matter which team or project is doing the work. They help keep things separate, so changes to one part of your infrastructure don&amp;#39;t accidentally mess up others. Modules can also bake in your organization&amp;#39;s best practices, security rules, and compliance standards right into the code. This means things automatically follow your guidelines. And because you can version modules, it helps stop &amp;quot;configuration drift&amp;quot; by making sure deployments always use a known, tested version of your infrastructure.&lt;/p&gt;
&lt;p&gt;Now, everyone knows modularity is key for following the &amp;quot;Don&amp;#39;t Repeat Yourself&amp;quot; (DRY) rule and keeping things consistent. But here&amp;#39;s a crucial point: if you use it wrong, you can actually create &lt;em&gt;new&lt;/em&gt; technical debt and make things more complicated. We often see &amp;quot;module sprawl&amp;quot; that&amp;#39;s when you have too many modules doing pretty much the same thing and &amp;quot;overuse of wrapper modules,&amp;quot; where you just wrap a simple resource in its own module without really adding much value. These habits can mean more work to maintain things, inconsistent deployments, and really tangled dependency chains. So, it&amp;#39;s not enough to just &lt;em&gt;have&lt;/em&gt; modules; they need to be &lt;em&gt;well-designed and managed properly&lt;/em&gt;. Without clear rules about &lt;em&gt;when&lt;/em&gt; to create a module and strong management practices, the very thing meant to simplify can actually make your infrastructure &lt;em&gt;less&lt;/em&gt; scalable and &lt;em&gt;harder&lt;/em&gt; to manage over time. This just goes to show that how your organization works and its design principles are just as important as the technical stuff itself.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s another cool thing about modular design: it helps you build a strong self-service system that naturally encourages compliance. By wrapping up complex setups and giving you a simpler way to interact with them, modules make it easier for other teams to get infrastructure, even if they&amp;#39;re not Terraform experts. HashiCorp even has &amp;quot;no-code ready modules&amp;quot; for this. What&amp;#39;s really important here is that by putting best practices, security policies, and compliance standards right into these modules companies can make sure any infrastructure set up using them automatically follows all the rules. This creates a self-service setup where developers can get their own infrastructure quickly and efficiently, &lt;em&gt;without&lt;/em&gt; needing to be security or compliance gurus. The design acts like a built-in safety net, cutting down on misconfigurations and making sure your infrastructure grows within set limits. That&amp;#39;s a huge win for both speed and good governance in big companies.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Building Robust Modules: Structure, Inputs, and Outputs&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To build strong, easy-to-maintain Terraform modules, you&amp;#39;ll want to stick to a standard structure and really think about how their interfaces work. A typical new module usually has &lt;code&gt;LICENSE&lt;/code&gt;, &lt;code&gt;README.md&lt;/code&gt;, &lt;code&gt;main.tf&lt;/code&gt;, &lt;code&gt;variables.tf&lt;/code&gt;, and &lt;code&gt;outputs.tf&lt;/code&gt; files. While you don&amp;#39;t &lt;em&gt;have&lt;/em&gt; to use this exact structure, it&amp;#39;s highly recommended. It makes your modules easier to reuse and maintain, and helps tools like the Terraform Registry understand and show your module&amp;#39;s info properly.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s what each file in that standard module structure is for:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;File/Directory&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;module-name/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The root directory for the module, containing all its configuration files.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;main.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This file holds the core resources and logic that the module provisions or manages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;variables.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This file declares the input variables, making the module configurable and adaptable to different scenarios.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputs.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This file defines the output values that the module exposes, allowing other configurations to consume information about the provisioned infrastructure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Provides comprehensive documentation on how to use the module, its purpose, inputs, and outputs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LICENSE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specifies the terms under which the module is distributed, crucial for shared modules.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;providers.tf&lt;/code&gt; (Optional)&lt;/td&gt;
&lt;td&gt;Specifies any required providers for the module, ensuring necessary plugins are available.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;examples/&lt;/code&gt; (Optional)&lt;/td&gt;
&lt;td&gt;Contains practical usage examples of the module, demonstrating how it can be implemented.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tests/&lt;/code&gt; (Optional)&lt;/td&gt;
&lt;td&gt;Includes automated tests for the module, ensuring its functionality and reliability.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Let&amp;#39;s look at a simple example of a Terraform module for creating an AWS S3 bucket. This module will create a bucket with versioning enabled and a specified access control list (ACL).&lt;/p&gt;
&lt;p&gt;First, you&amp;#39;d create a directory for your module, say &lt;code&gt;modules/s3-bucket/&lt;/code&gt;. Inside this directory, you&amp;#39;d have your &lt;code&gt;main.tf&lt;/code&gt;, &lt;code&gt;variables.tf&lt;/code&gt;, and &lt;code&gt;outputs.tf&lt;/code&gt; files.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# Core logic for creating an AWS S3 bucket with versioning.
resource &amp;quot;aws_s3_bucket&amp;quot; &amp;quot;this&amp;quot; {
  bucket = var.bucket_name
  acl    = var.acl
  tags   = var.tags # Allows for adding custom tags
}

resource &amp;quot;aws_s3_bucket_versioning&amp;quot; &amp;quot;this&amp;quot; {
  bucket = aws_s3_bucket.this.id

  versioning_configuration {
    status = var.versioning_enabled ? &amp;quot;Enabled&amp;quot; : &amp;quot;Suspended&amp;quot;
  }
}

# Optional: S3 bucket server-side encryption configuration
resource &amp;quot;aws_s3_bucket_server_side_encryption_configuration&amp;quot; &amp;quot;default&amp;quot; {
  bucket = aws_s3_bucket.this.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = &amp;quot;AES256&amp;quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# Input variables for the S3 bucket module.
variable &amp;quot;bucket_name&amp;quot; {
  description = &amp;quot;The name of the S3 bucket.&amp;quot;
  type        = string
}

variable &amp;quot;acl&amp;quot; {
  description = &amp;quot;The canned ACL to apply to the S3 bucket.&amp;quot;
  type        = string
  default     = &amp;quot;private&amp;quot;
}

variable &amp;quot;versioning_enabled&amp;quot; {
  description = &amp;quot;Enable or disable versioning for the S3 bucket.&amp;quot;
  type        = bool
  default     = true
}

variable &amp;quot;tags&amp;quot; {
  description = &amp;quot;A map of tags to add to the S3 bucket.&amp;quot;
  type        = map(string)
  default     = {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# Outputs for the S3 bucket module.
output &amp;quot;bucket_id&amp;quot; {
  description = &amp;quot;The ID of the S3 bucket.&amp;quot;
  value       = aws_s3_bucket.this.id
}

output &amp;quot;bucket_arn&amp;quot; {
  description = &amp;quot;The ARN of the S3 bucket.&amp;quot;
  value       = aws_s3_bucket.this.arn
}

output &amp;quot;bucket_domain_name&amp;quot; {
  description = &amp;quot;The domain name of the bucket.&amp;quot;
  value       = aws_s3_bucket.this.bucket_domain_name
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# Configure the AWS Provider
provider &amp;quot;aws&amp;quot; {
  region  = &amp;quot;us-west-2&amp;quot;
  # Optional: Use shared credentials and profile for local testing
  shared_credentials_files = [pathexpand(&amp;quot;~/.aws/credentials&amp;quot;)]
  profile                  = &amp;quot;TF_TEST_PROFILE&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# Root module configuration

# Define environment-specific variables
locals {
  environment = &amp;quot;dev&amp;quot; # Can be &amp;quot;dev&amp;quot;, &amp;quot;staging&amp;quot;, or &amp;quot;prod&amp;quot;
  common_tags = {
    Environment = local.environment
    Project     = &amp;quot;MyWebApp&amp;quot;
    ManagedBy   = &amp;quot;Terraform&amp;quot;
  }
}

# Call the S3 bucket module
module &amp;quot;my_website_bucket&amp;quot; {
  source  = &amp;quot;./modules/s3-bucket&amp;quot;

  bucket_name = &amp;quot;my-unique-bucket-${local.environment}&amp;quot; # Include environment in bucket name
  acl         = &amp;quot;private&amp;quot;
  versioning_enabled = local.environment == &amp;quot;prod&amp;quot; ? true : false # Enable versioning only in production
  tags = merge(local.common_tags, {
    Name = &amp;quot;MyWebApp-Bucket-${local.environment}&amp;quot;
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# Outputs from the root module
output &amp;quot;website_bucket_url&amp;quot; {
  description = &amp;quot;The URL of the S3 bucket.&amp;quot;
  value       = &amp;quot;https://${module.my_website_bucket.bucket_domain_name}&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;# Define variables for the root module
# No specific variables needed here as we are using locals
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, &lt;code&gt;module &amp;quot;my_website_bucket&amp;quot;&lt;/code&gt; references the &lt;code&gt;s3-bucket&lt;/code&gt; module you created. It passes values for &lt;code&gt;bucket_name&lt;/code&gt;, &lt;code&gt;acl&lt;/code&gt;, and &lt;code&gt;versioning_enabled&lt;/code&gt;. The &lt;code&gt;output &amp;quot;website_bucket_url&amp;quot;&lt;/code&gt; then uses an output from the module (&lt;code&gt;module.my_website_bucket.bucket_id&lt;/code&gt;) to construct a URL, showing how modules can pass information between different parts of your infrastructure setup.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;main.tf&lt;/code&gt; file usually holds the main resource definitions and logic. In &lt;code&gt;variables.tf&lt;/code&gt;, you declare your input variables, which makes the module customizable. If a variable doesn&amp;#39;t have a default value, it becomes a required input for anyone using your module. On the flip side, &lt;code&gt;outputs.tf&lt;/code&gt; defines the values that the module makes available to whatever calls it. A well-thought-out, stable interface with clear variable names, specific type rules, good descriptions, and useful outputs makes a module simple to understand, use, and fit into bigger setups. A poorly defined interface can lead to mistakes and a tough learning curve for people using your module. This really highlights that designing modules isn&amp;#39;t just about putting resources together; it&amp;#39;s about creating a clear agreement for how that piece of infrastructure will be used. Thinking &amp;quot;API-first&amp;quot; for your modules is vital for better teamwork, fewer mistakes, and making sure modules truly speed up development instead of causing headaches and technical debt. The &lt;code&gt;README.md&lt;/code&gt; file is also a big part of this &amp;quot;interface,&amp;quot; giving you important, easy-to-read documentation.&lt;/p&gt;
&lt;p&gt;Input variables are super important because they let you customize modules without changing their actual code, which helps you reuse them across different setups. They take values passed in from the module that&amp;#39;s calling them. For input variables, it&amp;#39;s best to use names that clearly describe what they&amp;#39;re for, set specific types for clarity, and provide smart default values for settings that don&amp;#39;t change between environments. You should avoid hardcoding values inside the module; instead, use variables to keep things flexible. Output values, though, send results back to the module that called them, which can then use those values to fill in other arguments. They&amp;#39;re essential for showing information about resources Terraform manages and are key for modules to talk to each other, and for displaying important info after you run terraform apply. For security, any sensitive outputs, like passwords, should be clearly marked as &lt;code&gt;sensitive = true&lt;/code&gt; so they don&amp;#39;t show up in plain text logs.&lt;/p&gt;
&lt;p&gt;You can use Terraform modules in two main ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Local Modules:&lt;/strong&gt; You load these from a path right on your local computer. They&amp;#39;re great for organizing and wrapping up code, even for projects just one person is working on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote Modules:&lt;/strong&gt; These come from outside sources like the Terraform Registry, version control systems (think Git), HTTP links, or private registries. Remote modules are perfect for reusing setups across lots of projects or teams, because sharing modules is a big part of reusing code and working together.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Module composition is about putting together several &amp;quot;building-block&amp;quot; modules to create a bigger, more complex system. We highly recommend keeping your module tree pretty flat, with just one level of child modules, instead of making deeply nested structures. You should define relationships between these modules using expressions, just like you&amp;#39;d link resources in a flat setup. This design idea, especially something called dependency inversion, directly fights the complexity that comes with deeply nested modules. It leads to infrastructure that&amp;#39;s more flexible and easier to maintain. Dependency inversion means a module gets its dependencies (like &lt;code&gt;vpc_id&lt;/code&gt;, &lt;code&gt;subnet_ids&lt;/code&gt;) as inputs from the main, or root, module, instead of trying to manage its own dependent resources internally. This makes things more flexible and lets you connect the same modules in different ways to get different results. It&amp;#39;s super handy when some objects might already exist in certain environments or when you&amp;#39;re building multi-cloud setups. This moves the job of arranging dependencies from inside the module to the configuration that&amp;#39;s calling it. This makes individual modules more self-contained and reusable, since they&amp;#39;re not tightly tied to how their dependencies are set up. The result is infrastructure code that&amp;#39;s more flexible and adaptable, easier to change over time, and reduces the &amp;quot;ripple effect&amp;quot; of changes, simplifying refactoring. That&amp;#39;s crucial for long-term scalability and keeping things running smoothly in ever-changing cloud environments.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s often tough to decide when to turn your code into a Terraform module versus just using a basic resource directly. Good abstraction is important, but wrapping things unnecessarily can just make them more complicated.&lt;/p&gt;
&lt;p&gt;You should create modules when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You find yourself copying the same kind of resource setup over and over this helps you stick to the DRY principle.&lt;/li&gt;
&lt;li&gt;A resource absolutely &lt;em&gt;needs&lt;/em&gt; specific configuration or metadata applied to it.&lt;/li&gt;
&lt;li&gt;A resource has strict or complex naming rules that &lt;em&gt;must&lt;/em&gt; be followed.&lt;/li&gt;
&lt;li&gt;A resource relies on information, metadata, or context that the user can&amp;#39;t know.&lt;/li&gt;
&lt;li&gt;The module will make your overall configuration or its interface simpler.&lt;/li&gt;
&lt;li&gt;Resources share a common business purpose or requirement.&lt;/li&gt;
&lt;li&gt;A bunch of resources have a similar lifecycle.&lt;/li&gt;
&lt;li&gt;Your goal is to consistently and repeatedly set up cloud resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the other hand, be careful or avoid modules when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You&amp;#39;re overusing &amp;quot;wrapper modules&amp;quot; where you just put a resource in a module without adding much real value. This can lead to huge, complex dependency chains and force new releases for tiny changes.&lt;/li&gt;
&lt;li&gt;A resource is &lt;em&gt;always&lt;/em&gt; going to be used by a higher-level module; in these cases, you probably shouldn&amp;#39;t make it a standalone or wrapper Terraform module.&lt;/li&gt;
&lt;li&gt;Too many modules could make your overall Terraform setup harder to understand and keep up with.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;Best Practices for Maintaining Healthy and Scalable Modular Terraform&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Keeping your modular Terraform environment healthy and scalable means you&amp;#39;ve got to be really careful about following best practices for versioning, state management, testing, and governance.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Versioning Strategies&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Good versioning is super important for keeping things stable and predictable. Terraform modules usually follow semantic versioning (MAJOR.MINOR.PATCH). The major version tells you about changes that aren&amp;#39;t backward-compatible, the minor version means new features that &lt;em&gt;are&lt;/em&gt; backward-compatible, and the patch version is for bug fixes that also &lt;em&gt;are&lt;/em&gt; backward-compatible. This system helps teams understand how big an update is and plan their upgrades carefully.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s really important to use version constraints (like &lt;code&gt;~&amp;gt; 1.2.0&lt;/code&gt;) in your module blocks. This helps make sure things are compatible and stops accidental problems from upgrades you haven&amp;#39;t tested. These constraints help Terraform pick the right versions automatically when you deploy. Also, regularly checking and updating Terraform and provider versions is vital to keep up with vendor improvements and security fixes. Automated tools like Dependabot and Renovate can really help with this. Plus, clear communication about planned upgrades, what might be affected, and testing schedules helps everyone on the team work together. For the most consistency and to avoid unexpected changes or configuration drift, sticking to strict version pinning (like &lt;code&gt;version = &amp;quot;1.2.3&amp;quot;&lt;/code&gt;) is a widely suggested practice.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;State Management in Modular Setups&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;You can&amp;#39;t talk enough about how important remote state is for secure Terraform operations where teams work together. You should always use remote state because it lets multiple team members share access, locks the state to stop simultaneous changes, and makes things more secure with encryption.&lt;/p&gt;
&lt;p&gt;Having ways to isolate state files is key to keeping risks low. We suggest using multiple state files for different parts of your infrastructure, logically separating resources. This really cuts down the &amp;quot;blast radius&amp;quot; of any mistake, meaning an error in one setup won&amp;#39;t mess up all your resources. Similarly, keeping separate state files for different environments (like development, staging, and production) gives you strong separation and stops accidental impacts across environments. When you&amp;#39;re using multiple state files, you&amp;#39;ll often need to refer to outputs from setups stored in different state files. You can do this using the &lt;code&gt;terraform_remote_state&lt;/code&gt; data source. And remember, you should never store state files in source control, because they contain plain text data that might include sensitive information.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Comprehensive Testing Methodologies&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Thorough testing is absolutely essential for making sure your IaC is reliable and high-quality in scalable environments. Different testing methods come with different costs, runtimes, and levels of depth:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Testing Method&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Tools/Approach&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cost/Runtime&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Static Analysis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Examines syntax, structure, and potential misconfigurations without deploying any actual resources.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;terraform validate&lt;/code&gt;, &lt;code&gt;tflint&lt;/code&gt;, &lt;code&gt;tfsec&lt;/code&gt;, &lt;code&gt;Checkov&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low / Fast&lt;/td&gt;
&lt;td&gt;Catches basic errors, security misconfigurations, and style issues early in the development cycle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Unit Testing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Focuses on testing individual modules in isolation, often using mock providers to simulate infrastructure.&lt;/td&gt;
&lt;td&gt;Terraform Test (built-in), mock providers&lt;/td&gt;
&lt;td&gt;Low / Fast (no real infrastructure)&lt;/td&gt;
&lt;td&gt;Verifies module logic and confirms expected outputs without provisioning actual cloud resources.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Module Integration Testing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Involves deploying individual modules into a dedicated test environment to verify resource creation and their intended functionality.&lt;/td&gt;
&lt;td&gt;Terratest, Kitchen-Terraform, InSpec, Google&amp;#39;s blueprint testing framework&lt;/td&gt;
&lt;td&gt;Medium / Moderate&lt;/td&gt;
&lt;td&gt;Ensures that modules function correctly as designed when deployed in a realistic context.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;End-to-End Testing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Extends integration testing by deploying the entire architecture (comprising multiple modules) into a fresh test environment that closely mirrors the production environment.&lt;/td&gt;
&lt;td&gt;Terratest, custom scripts&lt;/td&gt;
&lt;td&gt;High / Slow&lt;/td&gt;
&lt;td&gt;Confirms that all modules work together cohesively and that the complete system behaves as expected in a near-production setting.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Tools like &lt;code&gt;terraform validate&lt;/code&gt; do static analysis to check your syntax and make sure your configuration is valid. Terratest, which is a Go-based framework, is widely used for integration and end-to-end testing. It&amp;#39;s flexible, works well with CI/CD pipelines, and saves you money because it only sets up infrastructure while the tests are running. There&amp;#39;s also a newer, built-in option called Terraform Test, which is an HCL-based unit testing feature available in Terraform v15+. It lets your tests live right next to your main code and uses mock providers for testing that won&amp;#39;t cost you anything, since you don&amp;#39;t need to set up actual infrastructure.&lt;/p&gt;
&lt;p&gt;There are a few practical things to keep in mind for good testing. Tests can create, change, and destroy real infrastructure, so they can take a lot of time and cost money. To help with this, it&amp;#39;s smart to break your architecture into smaller modules and test each one separately. This makes tests faster, cheaper, and more reliable. Ideally, each test should be independent, so you&amp;#39;re not reusing state across tests. Taking a &amp;quot;fail fast&amp;quot; approach by running cheaper methods (like static analysis and unit tests) first helps you catch problems early. Always use a separate, isolated environment for testing to stop accidental deletions or changes to your development or production resources. And super important: make sure all resources are completely cleaned up after testing so you don&amp;#39;t get hit with unnecessary cloud bills.&lt;/p&gt;
&lt;p&gt;Focusing on static analysis, unit testing (especially with mock providers), and policy enforcement shows a strong move towards &amp;quot;shifting left&amp;quot; quality and security checks in IaC pipelines. This means finding and fixing problems everything from syntax errors and wrong setups to security holes and policy breaches earlier in the development process, often even before you run any &lt;code&gt;terraform plan&lt;/code&gt; or &lt;code&gt;apply&lt;/code&gt; command. This proactive way of working really cuts down the cost of fixing bugs, speeds up development, and naturally makes your infrastructure more secure and compliant by catching issues when they&amp;#39;re easiest and cheapest to sort out. It&amp;#39;s a big change from just reacting to problems to actively making sure things are good from the start.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Governance and Security&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Strong governance and security are super important for big IaC deployments. Putting clear approval steps in your workflow, especially for module or resource upgrades, is a critical way to lower the risk of accidentally breaking things. This gives you an essential extra layer of review for big changes. You should also use the &lt;code&gt;prevent_destroy&lt;/code&gt; feature to protect against accidentally deleting resources.&lt;/p&gt;
&lt;p&gt;Automated governance, especially with tools like Open Policy Agent (OPA), is a strong way to fight the problems of module sprawl, misconfigurations, and security weaknesses in big IaC setups. OPA can define, enforce, and check policies across your infrastructure configurations. For instance, OPA policies can make sure you only use approved module sources and registries, require strict module version pinning, demand specific modules for critical resource types, and point out when deprecated or insecure modules are being used. This automated policy enforcement gives you automatic safety rails, making sure developers stick to your defined dependency management practices and company standards. This complete governance framework directly solves the issues of module sprawl and reduces related risks by making sure things are consistent and secure right from the start.&lt;/p&gt;
&lt;p&gt;Good security practices also mean protecting hard-coded secrets by not putting credentials directly in your code. Instead, you should use sensitive variable references or special tools for managing secrets. Regularly scanning your IaC setups for misconfigurations using static application security testing (SAST) or software composition analysis (SCA) tools is super important to find potential weaknesses that could leave your infrastructure open to attack.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Thorough documentation is vital for keeping modular Terraform easy to maintain and use. Every module should have a clear &lt;code&gt;README.md&lt;/code&gt; file that explains its purpose, inputs, outputs, dependencies, and how to use it. Keeping changelogs is also important to track big changes, giving module users clear info on updates. Plus, clearly documenting version requirements and constraints in your project docs makes sure team members know about compatibility needs.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Modular Terraform isn&amp;#39;t just a nice-to-have technical feature; it&amp;#39;s a core strategy for building strong, scalable, and easy-to-maintain Infrastructure as Code. By adopting modular design, companies can change how they manage infrastructure from a manual, mistake-prone process into something automated, consistent, and super efficient.&lt;/p&gt;
&lt;p&gt;Your journey starts with really understanding Infrastructure as Code principles, using Terraform&amp;#39;s declarative power and its key parts. But the real scalability and ease of management come from well-designed modules that hide complexity, encourage reuse, and make sure things are consistent across different environments. Sticking to a structured module design, carefully defining inputs and outputs, and smartly using module composition are all vital steps here.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s more, keeping a healthy modular Terraform ecosystem needs ongoing work. This means putting in place strict versioning strategies, managing state files remotely and securely, using thorough testing methods (from static analysis to full end-to-end checks), and setting up strong governance frameworks. Together, these practices help reduce common problems like configuration sprawl, dependency management, and security weaknesses.&lt;/p&gt;
&lt;p&gt;Ultimately, by sticking to modular Terraform best practices, companies can gain incredible speed, cut down on operational risks, save money, and build a resilient cloud infrastructure that can support fast innovation and growth. It&amp;#39;s an investment that really pays off in terms of reliability, efficiency, and the confidence to scale operations in a constantly changing digital world.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Creating Modules | Terraform | HashiCorp Developer, accessed on June 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/terraform/language/modules/develop&quot;&gt;https://developer.hashicorp.com/terraform/language/modules/develop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Build and use a local module | Terraform | HashiCorp Developer, accessed on June 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/terraform/tutorials/modules/module-create&quot;&gt;https://developer.hashicorp.com/terraform/tutorials/modules/module-create&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Modules overview | Terraform | HashiCorp Developer, accessed on June 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/terraform/tutorials/modules/module&quot;&gt;https://developer.hashicorp.com/terraform/tutorials/modules/module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform Infrastructure as Code (IaC) Guide With Examples - Spacelift, accessed on June 6, 2025, &lt;a href=&quot;https://spacelift.io/blog/terraform-infrastructure-as-code&quot;&gt;https://spacelift.io/blog/terraform-infrastructure-as-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Managing Terraform State - Best Practices &amp;amp; Examples - Spacelift, accessed on June 6, 2025, &lt;a href=&quot;https://spacelift.io/blog/terraform-state&quot;&gt;https://spacelift.io/blog/terraform-state&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform Modules: Mastering IaC Efficiency - Coherence, accessed on June 6, 2025, &lt;a href=&quot;https://www.withcoherence.com/articles/terraform-modules-mastering-iac-efficiency&quot;&gt;https://www.withcoherence.com/articles/terraform-modules-mastering-iac-efficiency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Best practices for general style and structure | Terraform - Google Cloud, accessed on June 6, 2025, &lt;a href=&quot;https://cloud.google.com/docs/terraform/best-practices/general-style-structure&quot;&gt;https://cloud.google.com/docs/terraform/best-practices/general-style-structure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Best practices for testing | Terraform | Google Cloud, accessed on June 6, 2025, &lt;a href=&quot;https://cloud.google.com/docs/terraform/best-practices/testing&quot;&gt;https://cloud.google.com/docs/terraform/best-practices/testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform Module Versioning Best Practices - Prospera Soft, accessed on June 6, 2025, &lt;a href=&quot;https://prosperasoft.com/blog/devops/terraform/terraform-module-versioning-best-practices/&quot;&gt;https://prosperasoft.com/blog/devops/terraform/terraform-module-versioning-best-practices/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Platform Engineer&amp;#39;s Guide to Sustainable Module Management, accessed on June 6, 2025, &lt;a href=&quot;https://www.scalr.com/guides/platform-engineers-guide-to-sustainable-module-management&quot;&gt;https://www.scalr.com/guides/platform-engineers-guide-to-sustainable-module-management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Terraform &amp;amp; Infrastructure as Code (IaC)? - Pluralsight, accessed on June 6, 2025, &lt;a href=&quot;https://www.pluralsight.com/resources/blog/cloud/what-is-terraform-infrastructure-as-code-iac&quot;&gt;https://www.pluralsight.com/resources/blog/cloud/what-is-terraform-infrastructure-as-code-iac&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cloud infrastructure provisioning: best practices for IaC - ISE, accessed on June 6, 2025, &lt;a href=&quot;https://devblogs.microsoft.com/ise/best-practices-infrastructure-pipelines/&quot;&gt;https://devblogs.microsoft.com/ise/best-practices-infrastructure-pipelines/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform; to module, or not to module - Brendan Thompson, accessed on June 6, 2025, &lt;a href=&quot;https://brendanthompson.com/terraform-to-module-or-not-to-module/&quot;&gt;https://brendanthompson.com/terraform-to-module-or-not-to-module/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Testing Terraform Code Part Two: Unit and Integration Testing, accessed on June 6, 2025, &lt;a href=&quot;https://www.flowfactor.be/blogs/testing-terraform-code-part-two-unit-and-integration-testing/&quot;&gt;https://www.flowfactor.be/blogs/testing-terraform-code-part-two-unit-and-integration-testing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Is Infrastructure as Code (IaC)? | CrowdStrike, accessed on June 6, 2025, &lt;a href=&quot;https://www.crowdstrike.com/en-us/cybersecurity-101/cloud-security/infrastructure-as-code-iac/&quot;&gt;https://www.crowdstrike.com/en-us/cybersecurity-101/cloud-security/infrastructure-as-code-iac/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Infrastructure as Code</category><category>Terraform</category><category>DevOps</category><category>Cloud Engineering</category><category>Automation</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0095-modular-terraform-scalable-iac-guide/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Unmasking Hidden Costs: Your Guide to AWS Cost Optimization Cleanup Strategies</title><link>https://mkabumattar.com/blog/post/aws-cost-optimization-cleanup-strategies/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/aws-cost-optimization-cleanup-strategies/</guid><description>Unlock significant savings in AWS by implementing effective cleanup strategies. This guide covers identifying hidden costs, practical cleanup actions for EC2, EBS, S3, RDS, and more, and how to leverage automation with Cost Explorer, Cloud Custodian, and spot instances for continuous optimization. Learn to reduce waste and maximize your AWS investment.</description><pubDate>Sat, 07 Feb 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The cloud offers amazing flexibility and scalability, letting businesses innovate and grow super fast. But if you&amp;#39;re not careful, those benefits can quickly lead to surprisingly high bills. Lots of companies end up paying for stuff they don&amp;#39;t even use, which is a huge waste. In fact, studies show businesses often waste about 32% of their cloud money on things like having too much capacity, idle resources, or inefficient setups. This really shows something important about using the cloud: AWS&amp;#39;s dynamic, pay-as-you-go style, while super powerful, can also make your costs spiral if you don&amp;#39;t manage it smartly. It&amp;#39;s not just about cutting costs; it&amp;#39;s about making sure every dollar you spend in AWS actually brings real value to your business.&lt;/p&gt;
&lt;p&gt;Think of AWS cost optimization as an ongoing journey, not a quick fix. It means smartly cutting down AWS costs while making sure your apps still run great, stay secure, and are reliable. The goal is to get the most out of your cloud investments, making sure every dollar spent lines up with your business goals and helps fund new growth. This bigger picture turns cost optimization from just a tech task into something vital for the business, pushing for a more complete and proactive approach instead of just cutting costs when things get bad. This guide will walk you through practical, cost-focused cleanup strategies for your AWS setup. We&amp;#39;ll explore how to spot unnecessary spending, dive into specific cleanup actions for common AWS services, show you how to automate these efforts for long-term savings, and share tips for building a cost-aware culture.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why Does AWS Cost Optimization Matter So Much?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;At its core, AWS cost optimization is all about making smart choices to get the most value from your cloud investment. It&amp;#39;s an ongoing process of finding and cutting down wasteful spending, underused resources, and low returns on your IT budget. This means making processes smoother, getting your workloads to run better, and using automation to manage resources efficiently. Ultimately, it lowers cloud costs while still giving you great performance. The official AWS docs point out several benefits, like flexible purchase options through AWS Free Tier, volume discounts, Savings Plans, Reserved Instances, and Spot Instances. They also highlight better resource use and flexible provisioning for changing demand, all of which help you get a better price for the performance you get.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Common Sources of Cloud Waste: The Hidden Drains&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Even with the pay-as-you-go model, if you don&amp;#39;t keep an eye on your resource usage, you&amp;#39;ll often end up with unexpected costs. The main reasons for high AWS bills are often subtle, slowly building expenses that can quietly drain your budget. These often go unnoticed but add to your bill every single hour.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Underused Compute Instances:&lt;/strong&gt; Many EC2 instances are too big for what they need, meaning companies pay for way more CPU or memory than they actually use. AWS Trusted Advisor often points out instances running below 10% CPU use, which tells you they&amp;#39;re too big.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paying for Unused Resources:&lt;/strong&gt; This is a big source of waste. Things like Elastic Block Store (EBS) volumes, snapshots, and load balancers can stay active and cost you money even when they&amp;#39;re not attached to anything or handling traffic. For example, unassociated Elastic IPs cost money every hour if you&amp;#39;re not using them. Companies often forget to delete these inactive parts, which slowly builds up wasteful spending.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ignoring Discounted Pricing Models:&lt;/strong&gt; If you&amp;#39;re not using Spot Instances (which can save you up to 90%), Reserved Instances (up to 75% savings), or Savings Plans (up to 72% savings) for predictable or fault-tolerant workloads, you&amp;#39;re just leaving money on the table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inefficient Auto Scaling:&lt;/strong&gt; If your auto-scaling policies aren&amp;#39;t set up just right, they can create too many instances, adding resources you don&amp;#39;t need.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Suboptimal Storage Management:&lt;/strong&gt; Using expensive storage for data you don&amp;#39;t access often, or not deleting old snapshots, can really make your storage costs jump.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inefficient Data Transfer:&lt;/strong&gt; Unoptimized data transfer, especially moving data between regions or out to the internet, can lead to high bandwidth fees.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pay-as-you-go model, which gives you amazing agility and flexibility by letting you scale resources dynamically also means you get charged for every active resource, even if it&amp;#39;s just sitting there doing nothing. This dynamic nature makes cloud expenses tricky and hard to track without a clear plan. So, managing costs effectively takes ongoing effort and needs to be part of your daily operations, not just a one-time checklist.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How Can I Spot Unnecessary Spending in AWS? (Visibility &amp;amp; Detection)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Before you can clean anything up, you need to know what to clean. Seeing where your money goes is the first step to managing costs well. AWS gives you powerful built-in tools to help you clearly see your cloud spending and usage. Using these tools together gives you a powerful, complete way to find waste.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;AWS Cost Explorer: Your Financial Compass&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Cost Explorer is a main tool for seeing your AWS spending and usage with easy-to-understand graphs and charts. It lets you see where your money&amp;#39;s going, breaking down costs by services, accounts, regions, and even custom tags. This helps you pinpoint exactly what&amp;#39;s driving your costs.&lt;/p&gt;
&lt;p&gt;You can filter and group data by things like service, region, tags, and usage types. This detailed control helps you understand how and where resources are being used, and, importantly, find underused resources.&lt;/p&gt;
&lt;p&gt;Cost Explorer uses your past usage data to predict future costs for up to 12 months. This forecasting ability is super valuable for planning budgets and allocating resources effectively, helping you avoid unexpected financial burdens. This ability to see future costs coming and catch unexpected spikes before they become big problems helps you move from just reacting to issues to proactively managing your finances.&lt;/p&gt;
&lt;p&gt;Plus, you can set up alerts to spot unusual spending patterns, like a sudden jump in EC2 costs. This lets you investigate and fix things quickly, keeping your cloud spending on budget.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;AWS Trusted Advisor: Your Automated Auditor&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Trusted Advisor acts like an automated cloud consultant, checking your environment for cost optimization, security, performance, and fault tolerance. It&amp;#39;s especially good at flagging common cost problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idle Resources:&lt;/strong&gt; This includes things like orphaned EBS volumes, idle Load Balancers, and unassociated Elastic IPs, which keep costing you money.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Underused Instances:&lt;/strong&gt; Trusted Advisor can find EC2, RDS, or Redshift instances running below 10% CPU use, which means they&amp;#39;re too big.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unused Reserved Instances:&lt;/strong&gt; It helps find RIs that aren&amp;#39;t being used much, making sure you get the most out of your commitment savings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;AWS Compute Optimizer: Smart Sizing Recommendations&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This tool uses machine learning to look at how you&amp;#39;ve used resources in the past, like EC2 instances, EBS volumes, and Lambda functions. Then, it suggests the best setups to cut costs without hurting performance. For instance, it might suggest moving to a smaller EC2 instance type if your current one is consistently underused.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What Are the Key Cleanup Strategies for AWS Services? (Actionable Steps)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Once you can see your spending clearly, it&amp;#39;s time to act. Cleanup strategies mean going after specific types of waste across different AWS services. It&amp;#39;s important to remember that resources are connected, and deleting something without thinking about what it depends on can leave other resources running (and costing you money) or even lead to data loss. So, you need a cleanup approach that&amp;#39;s phased and aware of those dependencies.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;EC2 Instances: Right-Sizing and Smart Scheduling&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Right-Sizing:&lt;/strong&gt; This means making sure your compute resources (like CPU, memory, storage, and network speed) perfectly match what your application actually needs. Paying for a super-powerful instance when a regular one would do just fine just costs you extra money. Regularly looking at how you use things and adjusting instance sizes helps you avoid having too much capacity. AWS Compute Optimizer can help suggest the right size.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated Shutdown for Non-Production Environments:&lt;/strong&gt; For development, testing, or batch processing, you can save a lot by turning off instances during off-hours (like nights, weekends, and holidays). This can cut operating costs by up to 70%.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Using CloudWatch Alarms:&lt;/strong&gt; You can set up CloudWatch alarms to automatically shut down instances if they&amp;#39;re inactive. For example, an alarm can stop an instance if its CPU use stays below 3% for an hour. You have to be careful not to stop important background tasks that use little CPU; it&amp;#39;s a good idea to look at other metrics like network activity too.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using AWS Lambda with EventBridge:&lt;/strong&gt; For scheduled or batch processing of many instances, Lambda functions kicked off by EventBridge schedules are super efficient. You can tag instances for automatic shutdown, and a Lambda function can stop them at a specific time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using Spot Instances for Flexible Workloads:&lt;/strong&gt; Spot Instances give you huge discounts (up to 90% off On-Demand) for workloads that can handle interruptions, like batch jobs. They&amp;#39;re perfect for batch jobs, data analysis, or training AI models. Before you use them, it&amp;#39;s important to figure out if your workload can handle being interrupted.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;EBS Volumes: Deleting the Unattached&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Unused (unattached) EBS volumes keep costing you money even after their EC2 instances are gone. These are a common reason for unnecessary spending.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Finding Unused Volumes:&lt;/strong&gt; You can find these in the AWS EC2 dashboard by looking at the &amp;quot;State&amp;quot; column for volumes marked &amp;quot;available&amp;quot;. The AWS CLI command aws ec2 describe-volumes --filters Name=status,Values=available also works really well.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safely Deleting Unused Volumes:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Snapshotting Before Deletion (Optional but Recommended):&lt;/strong&gt; Always think about creating a snapshot of the volume before deleting it, just in case you need the data later. Amazon Data Lifecycle Manager can automate creating snapshots.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deletion:&lt;/strong&gt; Once you&amp;#39;ve taken a snapshot (or if you don&amp;#39;t need one), you can delete the volume using the EC2 console or the AWS CLI &lt;code&gt;aws ec2 delete-volume --volume-id [volume-id]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automating Cleanup with Lambda/CloudFormation:&lt;/strong&gt; For ongoing optimization, automate cleaning up unattached EBS volumes. A Lambda function, deployed through CloudFormation, can find and delete these volumes based on their &amp;quot;available&amp;quot; state. This makes sure your environment stays optimized without you having to do it by hand.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;S3 Storage: Tiering and Lifecycle Management&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;AWS has different S3 storage options, each with its own performance and cost. To optimize storage costs, you need to match how often you access data to the right storage tier.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;S3 Intelligent-Tiering:&lt;/strong&gt; This service automatically moves data to the cheapest storage tier based on how often it&amp;#39;s accessed, without affecting performance at all. It&amp;#39;s a &amp;quot;set it and forget it&amp;quot; solution for data access that changes over time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lifecycle Policies:&lt;/strong&gt; For data you access predictably, lifecycle policies are really powerful. You can set rules to:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Move Infrequently Accessed Data:&lt;/strong&gt; Automatically move objects to cheaper storage tiers like S3 Infrequent Access (S3 IA), S3 Glacier, or S3 Glacier Deep Archive after a certain number of days. S3 Analytics can help you find usage patterns and suggest moving data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delete Expired Objects/Delete Markers:&lt;/strong&gt; For buckets with versioning turned on, lifecycle rules can permanently delete old versions of objects and even clean up &amp;quot;expired object delete markers&amp;quot;. This is super important for avoiding charges for old versions or metadata.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;RDS Databases: Stopping Idle and Resizing&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Idle RDS instances can really drain your budget.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Finding and Stopping Idle RDS Instances:&lt;/strong&gt; Trusted Advisor&amp;#39;s &amp;quot;RDS Idle DB instances check&amp;quot; points out databases that haven&amp;#39;t had any connections for seven days. You can then stop these instances using the AWS Management Console or AWS CLI. Stopping an instance saves money, but deleting it means losing data, so you need to think carefully.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resizing Instances:&lt;/strong&gt; If an RDS instance isn&amp;#39;t being used much but you still need it, making it smaller and cheaper can cut costs without losing data. This takes your database offline for a bit, so you&amp;#39;ll need to plan for that.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Considering Serverless RDS:&lt;/strong&gt; For workloads that have unpredictable or bursty demand, Amazon Aurora Serverless can automatically scale down to almost no cost when it&amp;#39;s idle, making it super cost-efficient.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;Load Balancers &amp;amp; Elastic IPs: Cutting the Idle Fat&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deleting Unused Load Balancers:&lt;/strong&gt; Idle Load Balancers, especially ones not sending traffic or with very few requests (less than 100 over seven days), cost you money every hour. Trusted Advisor can find these. You can delete them through the EC2 console. It&amp;#39;s important to remember that deleting the load balancer doesn&amp;#39;t stop the EC2 instances connected to it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Releasing Unassociated Elastic IPs:&lt;/strong&gt; Elastic IP addresses cost money if they&amp;#39;re not connected to a running instance. Regularly checking for and releasing any unassociated EIPs helps you avoid these charges. Cloud Custodian has policies for this.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;Orphaned Resources: A Broader Cleanup&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Beyond the obvious, many other resources can become &amp;quot;orphaned&amp;quot; – meaning they&amp;#39;re no longer attached, referenced, or actively used but are still running.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Snapshots &amp;amp; AMIs:&lt;/strong&gt; Manual snapshots, especially after you delete an instance, can stick around and cost you money. Likewise, old AMIs can take up storage. AWS now has a feature that automatically deletes the EBS snapshots linked to an AMI when you deregister it, making cleanup simpler. This shows how AWS tools are evolving towards built-in cleanup automation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Groups &amp;amp; Network Interfaces:&lt;/strong&gt; Unused security groups can be a security risk and just clutter up your environment. Orphaned Elastic Network Interfaces (ENIs) also cost you money.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using AWS Config Rules for Detection:&lt;/strong&gt; AWS Config can constantly check your resource setups. Managed rules like &lt;code&gt;ec2-volume-inuse-check&lt;/code&gt; or &lt;code&gt;elastic-ip-attached&lt;/code&gt; can automatically find common orphaned resources. For more complex situations, you can use custom Config rules with Lambda functions to find resources that have been unattached for a certain amount of time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following table summarizes common sources of AWS waste and their corresponding cleanup strategies:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 1: Common AWS Waste &amp;amp; Cleanup Strategies&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;AWS Service&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Common Waste Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cleanup Strategy&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Key Tool/Method&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;EC2&lt;/td&gt;
&lt;td&gt;Underutilized/Idle Instances&lt;/td&gt;
&lt;td&gt;Right-sizing &amp;amp; Automated Shutdown&lt;/td&gt;
&lt;td&gt;Cost Explorer, CloudWatch, Lambda, EventBridge, Compute Optimizer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EBS&lt;/td&gt;
&lt;td&gt;Unattached Volumes&lt;/td&gt;
&lt;td&gt;Identify &amp;amp; Delete (with snapshots)&lt;/td&gt;
&lt;td&gt;Trusted Advisor, CLI, Lambda, CloudFormation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3&lt;/td&gt;
&lt;td&gt;Infrequently Accessed Data&lt;/td&gt;
&lt;td&gt;Lifecycle Policies &amp;amp; Intelligent-Tiering&lt;/td&gt;
&lt;td&gt;S3 Intelligent-Tiering, S3 Lifecycle Policies, S3 Analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RDS&lt;/td&gt;
&lt;td&gt;Idle Databases&lt;/td&gt;
&lt;td&gt;Stop Idle &amp;amp; Resize&lt;/td&gt;
&lt;td&gt;Trusted Advisor, Console, CLI, Aurora Serverless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load Balancers&lt;/td&gt;
&lt;td&gt;Unused Load Balancers&lt;/td&gt;
&lt;td&gt;Delete&lt;/td&gt;
&lt;td&gt;Trusted Advisor, Console, CLI, Cloud Custodian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Elastic IPs&lt;/td&gt;
&lt;td&gt;Unassociated EIPs&lt;/td&gt;
&lt;td&gt;Release&lt;/td&gt;
&lt;td&gt;Trusted Advisor, Console, CLI, Cloud Custodian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;General&lt;/td&gt;
&lt;td&gt;Lingering Snapshots, AMIs, Security Groups, ENIs&lt;/td&gt;
&lt;td&gt;Config Rules &amp;amp; Automated Deletion, New AMI Feature&lt;/td&gt;
&lt;td&gt;AWS Config, New AMI Feature, Cloud Custodian&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;How Can I Automate My AWS Cleanup Efforts? (Efficiency &amp;amp; Scale)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Doing cleanup by hand is a good start, but for ongoing and effective cost optimization, automation is a must. Automation lets you scale your efforts, cut down on human error, and make sure your cost policies are applied consistently. It&amp;#39;s absolutely necessary for cost optimization that can grow with your needs. As your AWS environment gets bigger, tasks that used to be simple can get complicated. Automation makes it easy to scale, helping you keep things efficient and secure no matter how large your AWS setup gets. It&amp;#39;s vital for keeping your costs tidy, like with scheduled shutdowns and snapshot cleanup.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;AWS Lambda &amp;amp; EventBridge: Event-Driven Cleanup&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;These services make a powerful pair for serverless, event-driven automation. Lambda functions can run code when different things happen, like on a schedule (through EventBridge) or when a resource&amp;#39;s state changes. For cleanup, this means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scheduling Regular Scans:&lt;/strong&gt; EventBridge can kick off a Lambda function on a schedule (like daily or weekly) to scan for and clean up idle resources such as EC2 instances or unattached EBS volumes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Responding to Resource Changes:&lt;/strong&gt; Lambda can, in theory, respond to events like &lt;code&gt;TerminateInstances&lt;/code&gt; or &lt;code&gt;DeleteDBInstance&lt;/code&gt; to trigger follow-up cleanup. For example, you can set up a Lambda function to find EC2 instances tagged for auto-stop and shut them down at a specific time every day. Another example is automatically deleting unattached EBS volumes using a Lambda function deployed through CloudFormation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;AWS Systems Manager: Maintenance Windows, Run Command, Custom Scripts&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;AWS Systems Manager gives you one place to handle operational tasks, including automation and cleanup.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maintenance Windows:&lt;/strong&gt; These let you set specific times for maintenance tasks, including cleaning up resources, without interrupting important services. You can schedule these windows, and register target resources using tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run Command:&lt;/strong&gt; Inside a Maintenance Window, you can assign tasks using &amp;quot;Run Command&amp;quot;. This lets you run scripts or AWS-provided automation documents on EC2 instances.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom Scripts (Boto3):&lt;/strong&gt; For unique cleanup needs, you can write custom scripts, often in Python using the Boto3 AWS SDK. These scripts can find and delete unused resources like ELBs, EC2 instances, or EBS volumes. Then, you package the scripts as SSM Documents (YAML or JSON) and run them through Systems Manager.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring:&lt;/strong&gt; Systems Manager sends execution logs to CloudWatch, so you can keep an eye on how your cleanup tasks are doing. You can even set up CloudWatch Alarms and SNS notifications for when tasks succeed or fail.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;Cloud Custodian: An Open-Source Policy Engine for Governance and Cleanup&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Cloud Custodian is a powerful open-source tool that lets you define policies (in YAML) to manage your AWS resources. It can query, filter, and act on resources for cloud security and governance.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Policy-Driven Automation:&lt;/strong&gt; Instead of writing complicated scripts, you define rules, like &amp;quot;delete unattached EBS volumes&amp;quot; or &amp;quot;terminate unused databases with no connections&amp;quot;. Cloud Custodian then automatically makes sure these policies are followed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Examples of Cleanup Policies:&lt;/strong&gt; Cloud Custodian offers a wide range of policies for different services:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EBS:&lt;/strong&gt; Policies like &amp;quot;Garbage Collect Unattached Volumes&amp;quot; and &amp;quot;Delete Unencrypted&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EC2:&lt;/strong&gt; &amp;quot;Offhours Support&amp;quot; for scheduled stopping, and &amp;quot;Terminate Unpatchable Instances&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RDS:&lt;/strong&gt; &amp;quot;Delete Unused Databases With No Connections&amp;quot; and &amp;quot;Terminate Unencrypted Public Instances&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;S3:&lt;/strong&gt; &amp;quot;Add Lifecycle Policy on Bucket Delete&amp;quot; and &amp;quot;Block Public S3 Object ACLs&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Elastic IPs:&lt;/strong&gt; &amp;quot;Garbage Collect Unattached Elastic IPs&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Groups:&lt;/strong&gt; Policies to make sure &amp;quot;Unused security groups are removed&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Load Balancers:&lt;/strong&gt; &amp;quot;Delete Unused Elastic Load Balancers&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; Cloud Custodian gives you a clear way to manage cloud hygiene, ensuring ongoing compliance and cost optimization across big, complex environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The range of automation solutions, from AWS tools like Lambda/EventBridge and Systems Manager to open-source options like Cloud Custodian, shows there isn&amp;#39;t just one &amp;quot;best&amp;quot; automation tool. Instead, you&amp;#39;ve got a whole spectrum of options, letting you build a layered automation strategy that fits your organization&amp;#39;s specific needs, current skills, and how much control and flexibility you want.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 2: AWS Cost Optimization Tools at a Glance&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Tool Name&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Primary Function&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Benefit for Cleanup/Optimization&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AWS Cost Explorer&lt;/td&gt;
&lt;td&gt;Cost Visualization &amp;amp; Forecasting&lt;/td&gt;
&lt;td&gt;Identifies cost drivers, anomalies, underutilized resources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Trusted Advisor&lt;/td&gt;
&lt;td&gt;Automated Best Practice Checks&lt;/td&gt;
&lt;td&gt;Flags idle/underutilized resources, unused RIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Compute Optimizer&lt;/td&gt;
&lt;td&gt;Resource Sizing Recommendations&lt;/td&gt;
&lt;td&gt;Recommends optimal instance/volume sizes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Lambda&lt;/td&gt;
&lt;td&gt;Serverless Event-Driven Compute&lt;/td&gt;
&lt;td&gt;Automates scheduled/event-driven cleanup scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon EventBridge&lt;/td&gt;
&lt;td&gt;Serverless Event Bus/Scheduler&lt;/td&gt;
&lt;td&gt;Triggers Lambda functions for scheduled cleanup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Systems Manager&lt;/td&gt;
&lt;td&gt;Operational Management &amp;amp; Automation&lt;/td&gt;
&lt;td&gt;Orchestrates cleanup tasks via Maintenance Windows/Run Command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud Custodian&lt;/td&gt;
&lt;td&gt;Policy-as-Code Governance&lt;/td&gt;
&lt;td&gt;Automates policy enforcement for cleanup across services&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;What Are the Best Practices for Sustainable Cost Optimization? (Long-Term Success)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Cost optimization isn&amp;#39;t just about applying a few quick fixes; it&amp;#39;s about building a cost-aware mindset and practices throughout your whole organization. This makes sure your savings last and grow over time.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Cultivating a FinOps Culture: Shared Responsibility and Cost Awareness&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Cloud Financial Management (FinOps) is a smart approach that gets everyone – from finance to engineering – involved in understanding and managing cloud costs. It builds a culture where technical decisions are made with an eye on the cost. When engineers get what things cost, they can build solutions that save money. This is a big cultural shift, bringing financial responsibility into technical decisions. Clearly defining who owns cloud spending and regularly sharing cost reports with your technical and business teams is super important.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Tagging Strategy: Allocating Costs Effectively&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Having a consistent tagging strategy for all your AWS resources from day one is incredibly important. Tags (which are just key-value pairs) let you categorize and track costs by project, department, team, or environment. This detailed allocation helps you pinpoint what&amp;#39;s driving costs, assign spending to specific business units or projects, and make decisions based on real data. Cost Explorer&amp;#39;s filtering and grouping features really depend on good tagging.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Continuous Monitoring and Iteration: Making Optimization an Ongoing Process&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Cost optimization is something you can measure and it&amp;#39;s an ongoing process. Regularly checking and analyzing usage with tools like AWS Cost Explorer helps you find new opportunities. Tracking how cost-efficient you are over time, and comparing past and current spending, helps you pinpoint inefficiencies. Dealing with cost anomalies quickly and tracking how your optimization efforts impact things is vital. This ongoing improvement makes sure every dollar you spend drives business value.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Security Considerations: Balancing Cost Savings with Operational Stability and Security&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While cutting costs is super important, it should never come at the cost of security or keeping things running smoothly. This means a delicate balancing act between &amp;quot;security&amp;quot; and &amp;quot;cost.&amp;quot;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Principle of Least Privilege (PoLP):&lt;/strong&gt; When cleaning up IAM roles or access keys, it&amp;#39;s vital to make sure you don&amp;#39;t remove permissions that are essential for critical operations. Giving only the minimum permissions needed is a fundamental security practice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Loss Prevention:&lt;/strong&gt; Be careful with deletions. For EBS volumes or RDS instances, think about creating final snapshots before permanently deleting them. This helps prevent accidental data loss.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Impact Assessment:&lt;/strong&gt; Before you automate any cleanup, thoroughly review your workload patterns to avoid accidentally stopping critical systems. Understanding how resources depend on each other is crucial to prevent unexpected operational problems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secure Automation:&lt;/strong&gt; It&amp;#39;s critical to make sure that IAM roles used by automation tools (like Lambda or Systems Manager) only grant the permissions they need for their tasks. Setting up security groups and Network Access Control Lists (NACLs) tightly makes things even more secure. Any cost optimization strategy needs to include a strong risk assessment and security review process to make sure that saving money doesn&amp;#39;t compromise the integrity, availability, or confidentiality of your cloud resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions (FAQs)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How often should I review my AWS costs?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cost optimization should be an ongoing process, not a one-time thing. While checking for anomalies daily with tools like Cost Explorer is helpful you should do a deeper review of cost reports and optimization recommendations at least weekly or monthly. This lets you track trends, find new inefficiencies, and make sure your cleanup strategies are working well. Consistent, regular review is key to staying in control of your cloud spending.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Is it safe to delete unused resources? What are the risks?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Deleting resources you truly don&amp;#39;t use is one of the quickest ways to save money. But you really need to be careful. The main risks are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Accidental Data Loss:&lt;/strong&gt; For things like EBS volumes or RDS instances, deleting them without taking a final snapshot can mean losing your data forever. Always take a snapshot first if you&amp;#39;re unsure whether you&amp;#39;ll need the data later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational Impact:&lt;/strong&gt; Deleting a resource that you actually still need (even if it&amp;#39;s idle) or that has hidden dependencies can break your applications or services. For instance, deleting a load balancer doesn&amp;#39;t automatically stop the EC2 instances connected to it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Gaps:&lt;/strong&gt; If you delete IAM roles or security groups incorrectly, you could accidentally create security holes or break legitimate access.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Always double-check that a resource is truly unused, understand what it depends on, and have a rollback plan (like snapshots) before deleting it.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can automation lead to accidental deletions&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, if automation isn&amp;#39;t carefully designed and tested, it can definitely lead to accidental deletions or unexpected problems. This is a big concern. To reduce this risk:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Thorough Testing:&lt;/strong&gt; Always test your automation scripts and policies (like Lambda functions or Cloud Custodian policies) in non-production environments first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Granular Permissions:&lt;/strong&gt; Make sure the IAM roles your automation uses follow the principle of least privilege, giving them only the permissions they absolutely need for their tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grace Periods/Notifications:&lt;/strong&gt; Put in grace periods before deletion (for example, mark for deletion, then delete after X days) and set up notifications (like via SNS) to alert teams before resources are removed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tagging:&lt;/strong&gt; Use tags to precisely target resources for automation, so you don&amp;#39;t accidentally mess with critical resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring and Logging:&lt;/strong&gt; Turn on detailed logging and monitoring (like CloudWatch Logs for Systems Manager/Lambda) to track what your automation is doing and quickly spot any issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What&amp;#39;s the difference between Reserved Instances, Savings Plans, and Spot Instances for cost saving?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;These are all pricing models that give you discounts, but they&amp;#39;re for different situations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reserved Instances (RIs):&lt;/strong&gt; Best for predictable, steady workloads. You commit to a specific instance type and region for 1 or 3 years, saving up to 75% compared to On-Demand pricing. They&amp;#39;re less flexible if your needs change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Savings Plans:&lt;/strong&gt; More flexible than RIs, they offer similar discounts (up to 72% for compute) but apply across different instance types, regions, and even services (like EC2, Lambda, Fargate). You commit to a consistent hourly spend (say, $10/hour for 1 or 3 years) instead of specific instance setups. They&amp;#39;re great for predictable compute usage with a bit of flexibility.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spot Instances:&lt;/strong&gt; These offer the biggest discounts, up to 90% off On-Demand pricing. They&amp;#39;re perfect for workloads that can handle interruptions, like batch jobs, data analysis, or training AI models. But AWS can take these instances back with short notice.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;AWS cost optimization isn&amp;#39;t just about cutting expenses; it&amp;#39;s a smart move that turns your cloud spending into a powerful way to grow your business and innovate. AWS&amp;#39;s flexibility, while a huge plus, also brings a challenge: &amp;quot;silent drains&amp;quot; from underused and idle resources that can quietly pile up significant costs. Tackling these requires a proactive and ongoing approach.&lt;/p&gt;
&lt;p&gt;Getting good at cost optimization really depends on having clear visibility, using tools like AWS Cost Explorer, Trusted Advisor, and Compute Optimizer to spot waste and find opportunities. Once you&amp;#39;ve found the waste, targeted cleanup strategies across services like EC2, EBS, S3, and RDS are key. This means going beyond just deleting things to include right-sizing, smart tiering, and lifecycle management. The way AWS&amp;#39;s own tools are evolving, like S3 Intelligent-Tiering and automated AMI snapshot deletion, shows a clear move towards building cleanup right into the platform, making less work for you.&lt;/p&gt;
&lt;p&gt;For long-term success that sticks, automation isn&amp;#39;t just nice to have; it&amp;#39;s a must. Solutions from native AWS Lambda and Systems Manager to open-source Cloud Custodian let organizations enforce policies widely, cut down on human error, and keep costs tidy all the time. This range of automation approaches lets organizations build a layered strategy that fits their specific needs.&lt;/p&gt;
&lt;p&gt;Ultimately, getting AWS cost optimization right means a cultural shift towards FinOps, where everyone thinks about costs in every technical decision. This, along with a consistent tagging strategy and continuous monitoring, forms the foundation of a cost-efficient cloud environment. Crucially, all your optimization efforts need to balance security and keeping things running smoothly, making sure that saving money doesn&amp;#39;t accidentally create risks or mess with your business operations. By embracing these ideas, organizations can get the most out of their AWS investments, turning potential hidden costs into smart advantages.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;AWS Cost Optimization | AWS Cloud Financial Management, accessed on June 6, 2025, &lt;a href=&quot;https://aws.amazon.com/aws-cost-management/cost-optimization/&quot;&gt;https://aws.amazon.com/aws-cost-management/cost-optimization/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Cost Optimization - How AWS Pricing Works, accessed on June 6, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/how-aws-pricing-works/aws-cost-optimization.html&quot;&gt;https://docs.aws.amazon.com/whitepapers/latest/how-aws-pricing-works/aws-cost-optimization.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Cost Optimization: Strategies, Tools, and Best Practices | B EYE, accessed on June 6, 2025, &lt;a href=&quot;https://b-eye.com/blog/aws-cost-optimization/&quot;&gt;https://b-eye.com/blog/aws-cost-optimization/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Cost Explorer: Basics, Use Cases, and Best Practices, accessed on June 6, 2025, &lt;a href=&quot;https://www.prosperops.com/blog/aws-cost-explorer/&quot;&gt;https://www.prosperops.com/blog/aws-cost-explorer/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Reduce IT costs by implementing automatic shutdown for Amazon EC2 instances, accessed on June 6, 2025, &lt;a href=&quot;https://aws.amazon.com/blogs/publicsector/reduce-it-costs-by-implementing-automatic-shutdown-for-amazon-ec2-instances/&quot;&gt;https://aws.amazon.com/blogs/publicsector/reduce-it-costs-by-implementing-automatic-shutdown-for-amazon-ec2-instances/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Delete Unattached &amp;amp; Unused EBS Volumes in AWS | nOps, accessed on June 6, 2025, &lt;a href=&quot;https://www.nops.io/unused-aws-ebs-volum/&quot;&gt;https://www.nops.io/unused-aws-ebs-volum/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Automated Solution to Delete Unused EBS Volumes | AWS re:Post, accessed on June 6, 2025, &lt;a href=&quot;https://repost.aws/fr/articles/ARjBj8O2SUTt2SX795RZOgQQ/automated-solution-to-delete-unused-ebs-volumes&quot;&gt;https://repost.aws/fr/articles/ARjBj8O2SUTt2SX795RZOgQQ/automated-solution-to-delete-unused-ebs-volumes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Example Policies Cloud Custodian documentation, accessed on June 6, 2025, &lt;a href=&quot;https://cloudcustodian.io/docs/aws/examples/index.html&quot;&gt;https://cloudcustodian.io/docs/aws/examples/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Remediate Amazon RDS Idle Instances | Stratusphere™, accessed on June 6, 2025, &lt;a href=&quot;https://stratusgrid.com/knowledge-base/how-to-remediate-amazon-rds-idle-instances-stratusphere&quot;&gt;https://stratusgrid.com/knowledge-base/how-to-remediate-amazon-rds-idle-instances-stratusphere&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Detecting Orphaned Resources Using AWS Config Rules, accessed on June 6, 2025, &lt;a href=&quot;https://www.cloudoptimo.com/blog/detecting-orphaned-resources-using-aws-config-rules/&quot;&gt;https://www.cloudoptimo.com/blog/detecting-orphaned-resources-using-aws-config-rules/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Automate AWS Cleanup with Systems Manager | SUDO, accessed on June 6, 2025, &lt;a href=&quot;https://sudoconsultants.com/how-to-automate-aws-resource-cleanup-with-aws-systems-manager-in-the-vast-expanse-of-cloud-computing/&quot;&gt;https://sudoconsultants.com/how-to-automate-aws-resource-cleanup-with-aws-systems-manager-in-the-vast-expanse-of-cloud-computing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Cost Optimization: 6 Best Practices For 2024 | CAST AI, accessed on June 6, 2025, &lt;a href=&quot;https://cast.ai/blog/aws-cost-optimization/&quot;&gt;https://cast.ai/blog/aws-cost-optimization/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Is Cost Optimization? 8 Best Practices To Use ASAP - CloudZero, accessed on June 6, 2025, &lt;a href=&quot;https://www.cloudzero.com/blog/cost-optimization/&quot;&gt;https://www.cloudzero.com/blog/cost-optimization/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon EC2 now enables you to delete underlying EBS snapshots when deregistering AMIs, accessed on June 6, 2025, &lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2025/06/amazon-ec2-delete-underlying-ebs-snapshots-deregistering-amis/&quot;&gt;https://aws.amazon.com/about-aws/whats-new/2025/06/amazon-ec2-delete-underlying-ebs-snapshots-deregistering-amis/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Getting Started With AWS Cost Explorer: Analyze, Manage, And Save, accessed on June 6, 2025, &lt;a href=&quot;https://cloudtweaks.com/2024/12/getting-started-with-aws-cost-explorer-analyze-manage-and-save/&quot;&gt;https://cloudtweaks.com/2024/12/getting-started-with-aws-cost-explorer-analyze-manage-and-save/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AWS</category><category>Cost Optimization</category><category>Cloud Financial Management</category><category>FinOps</category><category>Cloud Economics</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0094-aws-cost-optimization-cleanup-strategies/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Chaos Engineering: Testing Resiliency with Chaos Monkey and Gremlin</title><link>https://mkabumattar.com/blog/post/chaos-engineering-resiliency-testing-monkey-gremlin/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/chaos-engineering-resiliency-testing-monkey-gremlin/</guid><description>Master Chaos Engineering to build resilient systems. Explore how Chaos Monkey and Gremlin inject faults in AWS and Kubernetes, turning potential outages into proactive learning. Discover best practices, experiment types, and frequently asked questions for robust software testing.</description><pubDate>Sat, 31 Jan 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Modern software systems are incredibly complex. They&amp;#39;re spread across massive networks with countless moving parts. Because of this complexity, unexpected failures are inevitable. Servers crash. Networks slow down. Dependencies fail. Instead of waiting for something to break at 3 AM and scrambling to fix it, there&amp;#39;s a smarter approach: find and fix weaknesses before they cause real problems. That&amp;#39;s what Chaos Engineering is all about. As Dr. Werner Vogels, Amazon&amp;#39;s CTO, famously said, &amp;quot;Everything fails, all the time.&amp;quot; This simple truth is the foundation of an entire field dedicated to preparing systems for inevitable failures.&lt;/p&gt;
&lt;p&gt;Chaos Engineering is essentially a way to test how strong your system is by intentionally introducing faults. The goal? Find weak spots and fix them before they lead to real outages. It&amp;#39;s not about creating chaos for chaos&amp;#39;s sake. It&amp;#39;s a careful, scientific method that uses controlled experiments to identify and prevent problems before they happen. This approach fundamentally changes how companies think about system reliability. The old way was reactive: wait for something to fail, then fix it. That&amp;#39;s expensive in terms of downtime, reputation damage, and wasted resources. Chaos Engineering flips this around. It&amp;#39;s proactive. You&amp;#39;re preventing failures instead of just recovering from them. This shift represents a more mature engineering culture where prevention is valued over firefighting.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What Exactly is Chaos Engineering?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Chaos Engineering helps you understand how failures happen in complex systems and gives you practical ways to prevent or reduce them. At its core, it&amp;#39;s about running controlled experiments to uncover hidden weaknesses. Think of it like a vaccination for your software: you&amp;#39;re introducing a small, controlled problem to build immunity against bigger, real-world disasters.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the key difference between Chaos Engineering and traditional testing. Traditional testing verifies that your system works as expected. It&amp;#39;s checking known features and confirming requirements. You&amp;#39;re testing what you know. Chaos Engineering, on the other hand, looks for unknown weaknesses before they become problems. It&amp;#39;s proactive, not reactive.&lt;/p&gt;
&lt;p&gt;This shift matters more than you might think. Modern systems run in unpredictable environments with countless variables. Relying only on traditional testing leaves blind spots. You won&amp;#39;t know how robust your system really is until it&amp;#39;s under real pressure. By intentionally introducing controlled failures, you&amp;#39;ll discover which parts of your system are solid and which need work.&lt;/p&gt;
&lt;p&gt;This organized approach helps companies build stronger products, which directly impacts their bottom line and customer satisfaction. But there&amp;#39;s more to it than just technical benefits. When systems aren&amp;#39;t resilient enough, the hidden costs add up fast. You&amp;#39;re not just losing money during outages. You&amp;#39;re also slowly losing customer trust, burning out your operations team with constant incident response, exhausting developers who are always firefighting, and missing opportunities for innovation because your resources are tied up maintaining basic stability. Chaos Engineering tackles these problems early, creating a more sustainable and productive engineering environment.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why is System Resiliency So Crucial Today?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When we talk about resiliency in software, we&amp;#39;re talking about your system&amp;#39;s ability to keep working even when things go wrong. It might be running in a degraded state, but it&amp;#39;s still keeping core functions alive. More importantly, it&amp;#39;s about how quickly you can get back to normal operations. Real resilience means you can anticipate problems, absorb the impact, adapt to changes, and recover quickly from whatever the environment throws at you.&lt;/p&gt;
&lt;p&gt;In today&amp;#39;s hyper-connected world, even brief outages have massive consequences. Think about e-commerce during Black Friday, banking systems processing millions of transactions, or healthcare systems managing patient data. When these systems fail, the damage is immediate and severe. You&amp;#39;re looking at revenue losses, brand damage, frustrated customers, and potential regulatory penalties. The Digital Operational Resilience Act (DORA), for example, requires regular resiliency testing to identify weaknesses. This regulatory pressure isn&amp;#39;t going away. Building resilient systems isn&amp;#39;t optional anymore. It&amp;#39;s essential for protecting your business, your customers, and your reputation.&lt;/p&gt;
&lt;p&gt;The strategic importance of resilience goes way beyond technical features. It&amp;#39;s become a competitive differentiator and, increasingly, a regulatory requirement. System uptime and reliability directly drive customer satisfaction, revenue, and compliance. Companies that proactively invest in resilience using practices like Chaos Engineering are better positioned to meet strict regulations and outpace competitors by offering more stable, trustworthy services. Furthermore, there are often hidden costs associated with unaddressed system fragility. These extend beyond the immediate financial hit of an outage to include the gradual erosion of customer trust, increased operational overhead from constant incident response, developer burnout due to continuous firefighting, and the opportunity cost of being unable to innovate because resources are tied up in maintaining basic stability. By proactively identifying and rectifying these weaknesses, Chaos Engineering can substantially reduce these long-term, often unseen, expenses, contributing to a more sustainable and productive engineering organization.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What are the Guiding Principles of Chaos Engineering?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Chaos Engineering isn&amp;#39;t about randomly breaking things and seeing what happens. It&amp;#39;s a disciplined, scientific approach to understanding how systems behave under stress. These core principles guide how you design and run experiments, ensuring you get valuable insights instead of causing accidental damage.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build a Hypothesis Around Steady State Behavior:&lt;/strong&gt; Before introducing any disruption, you need to understand what normal looks like. Your steady state is the system&amp;#39;s baseline behavior, measured by key metrics like throughput, error rates, and response times. Once you&amp;#39;ve established this baseline, you form a hypothesis about how the system should behave when you introduce a specific fault. For example: &amp;quot;Even if our payment microservice fails, users can still browse products and add items to their cart.&amp;quot; This baseline is crucial for measuring the actual impact of your chaos experiments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mimic Real-World Problems:&lt;/strong&gt; Your experiments should simulate actual failures that happen in production environments. This ensures your insights are practical and actionable. Real-world problems include server crashes, network latency, database slowdowns, sudden traffic spikes, or third-party API failures. The more realistic your simulations, the more valuable your learnings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test in Production (or Production-like Environments):&lt;/strong&gt; Systems behave differently under real load with real traffic patterns. For the most accurate results, you should run experiments in production or in environments that closely mirror it. Yes, this sounds risky, but you&amp;#39;ll do it with strict safety controls to limit the blast radius. Start small in staging environments to build confidence, then gradually move to production with tight monitoring. The blast radius concept is critical here. By carefully controlling the scope of your experiments, you can isolate variables, observe specific impacts, and learn how your system reacts to particular faults without causing widespread damage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automate Your Chaos Tests:&lt;/strong&gt; Running experiments manually is time-consuming and doesn&amp;#39;t scale. Automation ensures tests run consistently and reliably. The best approach? Integrate chaos testing directly into your CI/CD pipeline. This way, you&amp;#39;re catching problems early during development and deployment, not after they reach production.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;One thing you absolutely can&amp;#39;t skip: strong monitoring and observability. Without good monitoring, you can&amp;#39;t define your steady state, measure the impact of experiments, or detect when something goes wrong. Investing in comprehensive monitoring and logging is both a prerequisite and an ongoing requirement for successful Chaos Engineering.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s another benefit that&amp;#39;s often overlooked. Chaos Engineering makes your team operationally stronger. By regularly simulating failures, teams practice incident response, test their alerting systems, and sharpen their debugging skills. This regular exposure to stress builds confidence and creates a more mature, resilient engineering team. You&amp;#39;re not just finding system bugs. You&amp;#39;re also uncovering and fixing gaps in your operational processes and team readiness.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Chaos Monkey: The Original Primate of Production Chaos&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Chaos Monkey was born out of necessity at Netflix. As they pioneered cloud-native architecture, they faced a critical challenge: keeping their streaming service available while running on thousands of cloud servers. Their solution? Build a tool that randomly shuts down instances in production. Sounds crazy, right? But this seemingly destructive action had a powerful purpose. It forced engineers to design services that could handle instance failures from day one. The tool exposed engineers to failures frequently, encouraging them to build naturally resilient services.&lt;/p&gt;
&lt;p&gt;Chaos Monkey&amp;#39;s job is simple: randomly terminate virtual machine instances and containers during specific time windows. While its main action is random termination, you can customize its behavior through configuration files and integration with Spinnaker (Netflix&amp;#39;s continuous delivery platform). It includes an outage checker that prevents it from running during existing incidents, so it won&amp;#39;t make ongoing problems worse.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a basic example of a Chaos Monkey configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Chaos Monkey configuration for AWS
accounts:
  - name: production
    enabled: true
    # Only run during business hours (PST)
    schedule:
      enabled: true
      startHour: 9
      endHour: 17
      timezone: America/Los_Angeles

terminationStrategy:
  # Randomly terminate instances
  randomSelection: true

  # Probability of termination (10% chance)
  probability: 0.1

  # Maximum number of instances to terminate per run
  maxTerminationsPerDay: 5

# Exclude critical services
exceptions:
  - serviceName: auth-service
  - serviceName: payment-processor

# Notification settings
notifications:
  email:
    - devops@example.com
  slack:
    channel: &amp;#39;#chaos-engineering&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Despite its historical significance, Chaos Monkey has some significant limitations. Its biggest constraint is limited attack types. It only does one thing: random instance termination. This seriously limits the kinds of failure scenarios you can simulate. The unpredictable, completely random nature means you have limited control over the blast radius. This lack of precision can cause more harm than good if your system isn&amp;#39;t ready.&lt;/p&gt;
&lt;p&gt;Chaos Monkey also has major dependencies. It needs Spinnaker and MySQL for full integration. A big downside? Netflix no longer actively develops or maintains it, making it less practical for teams looking for ongoing support and new features. It also lacks built-in recovery or rollback mechanisms. Any fault tolerance or outage detection requires custom code.&lt;/p&gt;
&lt;p&gt;Chaos Monkey works with environments that Spinnaker supports: AWS, Google Compute Engine (GCE), Azure, and Kubernetes. It&amp;#39;s been specifically tested with AWS, GCE, and Kubernetes. If your applications are managed through Spinnaker, you can set up Chaos Monkey to terminate instances within these cloud and container platforms.&lt;/p&gt;
&lt;p&gt;The evolution from Chaos Monkey to modern tools shows a shift from forced resilience to controlled learning. Chaos Monkey&amp;#39;s original idea was revolutionary in its simplicity. By randomly terminating instances, it forced engineers to build resilience into their services. But its limitations (just one random fault type and no ongoing maintenance) show that while random disruption can uncover weaknesses, lasting resilience needs a more controlled, varied, and analytical approach. The industry has moved from a raw break it to see what happens mindset to a more mature, controlled, and data-driven experimental science.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Gremlin: The Modern Platform for Controlled Chaos&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Gremlin stands out as a leading cloud-native platform built specifically to make Chaos Engineering safe, easy, and secure. Its main goal? Improve system uptime, validate reliability, and help companies build a strong reliability culture. Unlike Chaos Monkey&amp;#39;s random approach, Gremlin gives you precise control over fault injection.&lt;/p&gt;
&lt;p&gt;Gremlin provides an extensive fault injection library that lets you simulate real-world failures across different system layers:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resource Attacks:&lt;/strong&gt; These test how your system handles resource constraints.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU attacks stress test high-demand scenarios&lt;/li&gt;
&lt;li&gt;Memory attacks check for leaks or resource-heavy applications&lt;/li&gt;
&lt;li&gt;I/O attacks create read/write pressure to test storage performance&lt;/li&gt;
&lt;li&gt;GPU attacks stress AI, LLM, and video encoding workloads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s a simple example of running a CPU attack with Gremlin:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash

# Attack all cores on a specific container for 60 seconds
gremlin attack-container \
  --container-id abc123 \
  --type cpu \
  --cores 0 \
  --length 60
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Network Attacks:&lt;/strong&gt; These simulate network problems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blackhole attacks drop all network traffic to simulate complete outages&lt;/li&gt;
&lt;li&gt;Latency attacks inject delays to test responsiveness under slow networks&lt;/li&gt;
&lt;li&gt;Packet Loss attacks drop or corrupt traffic to mimic poor network conditions&lt;/li&gt;
&lt;li&gt;DNS attacks block DNS access to test fallback mechanisms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s how to inject network latency:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash

# Add 100ms latency to all egress traffic for 2 minutes
gremlin attack-container \
  --container-id abc123 \
  --type latency \
  --delay 100 \
  --length 120
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Attacks:&lt;/strong&gt; These test application and system state changes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Process Killer stops specific processes to simulate application crashes&lt;/li&gt;
&lt;li&gt;Shutdown attacks restart the host OS to test host failure recovery&lt;/li&gt;
&lt;li&gt;Time Travel attacks change system time to test for clock drift or certificate expiry&lt;/li&gt;
&lt;li&gt;Certificate checks verify certificate chains for expiration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s a process killer example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash

# Kill all nginx processes and repeat every 5 seconds for 2 minutes
gremlin attack-container \
  --container-id abc123 \
  --type process_killer \
  --process nginx \
  --interval 5 \
  --length 120
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can combine these attack types to create hundreds of pre-built and custom scenarios for very targeted, complex simulations.&lt;/p&gt;
&lt;p&gt;Gremlin&amp;#39;s platform supports multi-environment deployments. It&amp;#39;s truly cloud-native and runs almost anywhere: all major public clouds (AWS, Azure, GCP), Linux, Windows, containerized environments like Kubernetes, and even on-premise with Gremlin Private Edition. This wide compatibility makes it versatile for companies with diverse infrastructure.&lt;/p&gt;
&lt;p&gt;Beyond fault injection, Gremlin offers features that enhance your Chaos Engineering practice. Its GameDay Manager helps organize reliability events, cutting down prep and execution time. The platform automatically analyzes and stores experiment results, so teams can review outcomes and turn data into real improvements. It integrates with Jira for efficient action item tracking. Gremlin also provides reliability scoring and continuous risk monitoring, helping you define, measure, and track service reliability across your organization. It can automatically discover and test system dependencies, giving you deeper insights into system weaknesses.&lt;/p&gt;
&lt;p&gt;Gremlin&amp;#39;s extensive feature set (from diverse fault types and multi-cloud support to GameDay management and Jira integration) shows that Chaos Engineering has matured into a complete managed service. This evolution reflects the growing complexity of modern systems and the increasing need for advanced reliability management.&lt;/p&gt;
&lt;p&gt;What makes Gremlin particularly valuable is its focus on safety and control. By positioning itself as making Chaos Engineering safe, easy, and secure, Gremlin directly addresses common concerns about the practice. Many teams worry about causing more harm than good. By offering precise control over fault injection, automatic halt and rollback features, and a user-friendly interface, Gremlin transforms a potentially risky practice into a controlled, value-generating activity. This changes how willing businesses are to adopt these methods, especially in sensitive production environments.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Chaos Monkey vs. Gremlin: Which Tool is Right for You?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Choosing between Chaos Monkey and Gremlin depends on your company&amp;#39;s specific needs, budget, and chaos engineering maturity. While both tools aim to make systems more resilient, their approaches and capabilities are quite different.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a side-by-side comparison:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature/Aspect&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Chaos Monkey&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Gremlin&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Origin &amp;amp; Maintenance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Developed by Netflix, historically significant. No longer actively developed or maintained.&lt;/td&gt;
&lt;td&gt;Commercial product, actively developed and maintained.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Control Over Faults&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Injects faults randomly, giving a more realistic test environment for broad resilience. Limited control over blast radius and execution.&lt;/td&gt;
&lt;td&gt;Offers precise control over fault injection, allowing targeted experiments. Provides automatic halt and rollback mechanisms.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Types of Faults&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Primarily one attack type: random instance termination (shutdown).&lt;/td&gt;
&lt;td&gt;Wide range of fault types: CPU, Memory, Disk, I/O, Blackhole, Latency, Packet Loss, Process Killer, Shutdown, DNS, Time Travel, Certificate Expiry, GPU.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloud/Environment Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tightly integrated with Netflix OSS and AWS. Works with AWS, GCE, and Kubernetes via Spinnaker. Limited multi-cloud or hybrid cloud support.&lt;/td&gt;
&lt;td&gt;Cloud-native platform supporting all public clouds (AWS, Azure, GCP), Linux, Windows, Kubernetes, and on-premise environments.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easy to set up and use for its specific function. Requires Spinnaker and MySQL for full integration.&lt;/td&gt;
&lt;td&gt;User-friendly web interface and CLI. May require more initial setup and configuration than Chaos Monkey.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free and open-source.&lt;/td&gt;
&lt;td&gt;Requires payment for advanced features and enterprise use.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reporting &amp;amp; Analytics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No built-in detailed reporting or analysis; requires custom code for outage detection and fault tolerance.&lt;/td&gt;
&lt;td&gt;Offers rich analytics and visualization tools, automatic analysis, and storage of results. Integrates with Jira for action item tracking.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Safety &amp;amp; Risk Mitigation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;May cause system downtime and false positives. High risk if unprepared due to randomness.&lt;/td&gt;
&lt;td&gt;Designed for safety and security. Allows starting small and scaling experiments, with features to confidently recreate incidents.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Additional Features&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Basic functionality for instance termination.&lt;/td&gt;
&lt;td&gt;GameDay Manager, scenario sharing, scheduled scenarios, reliability scoring, dependency discovery, failure flags, private edition.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;This table gives you a clear, easy-to-scan comparison for quickly grasping the main differences and trade-offs.&lt;/p&gt;
&lt;p&gt;When choosing between these tools, consider your priorities. If cost is your main concern and you only need basic random instance termination, Chaos Monkey (or similar open-source tools like Pumba for Docker/Kubernetes) could be a good starting point. However, if you need precise control over fault injection, diverse fault types, full multi-cloud support, advanced features like GameDay management, and detailed analytics, Gremlin is the stronger choice for enterprise-level reliability efforts.&lt;/p&gt;
&lt;p&gt;Ultimately, your decision should factor in your team&amp;#39;s chaos engineering maturity, available budget, and the complexity of the systems you&amp;#39;re testing. The clear difference between Chaos Monkey and Gremlin reflects how Chaos Engineering has become a commercial and professional discipline. What started as an internal Netflix experiment has grown into a dedicated industry with advanced platforms, showing the growing recognition that reliability is a core business function.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How Do We Inject Chaos in AWS Environments?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In AWS environments, Chaos Engineering follows a structured framework designed to find resilience gaps in your workloads. It&amp;#39;s not about randomly breaking production systems. It&amp;#39;s a valuable tool for understanding how your workloads behave under simulated failure conditions.&lt;/p&gt;
&lt;p&gt;The most common approach uses the AWS Fault Injection Simulator (FIS), a managed service built specifically for running chaos engineering experiments on AWS services. Here&amp;#39;s the typical workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define Steady State:&lt;/strong&gt; First, define the normal operating condition for your systems. This baseline lets you measure what happens when you inject chaos. Collect and analyze data during stable conditions to set performance baselines and identify normal behavior patterns.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Design Chaos Tests:&lt;/strong&gt; Plan controlled chaos experiments to simulate different failure scenarios within that steady state. Identify specific components or services to target and determine the experiment&amp;#39;s scope and severity. AWS FIS is perfect for this.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Execute Experiments:&lt;/strong&gt; Set up the necessary infrastructure for running tests, including test environments, monitoring, and logging systems. Then run your defined experiments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analyze and Fix:&lt;/strong&gt; During experiments, continuously monitor system behavior. Collect and analyze data to assess performance, stability, and resilience impacts, comparing against your baselines.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Iterate and Improve:&lt;/strong&gt; Repeat these steps periodically to ensure your system remains resilient over time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;#39;s a practical example using AWS FIS to terminate EC2 instances:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;description&amp;quot;: &amp;quot;Test application resilience by terminating EC2 instances&amp;quot;,
  &amp;quot;targets&amp;quot;: {
    &amp;quot;ec2-instances&amp;quot;: {
      &amp;quot;resourceType&amp;quot;: &amp;quot;aws:ec2:instance&amp;quot;,
      &amp;quot;resourceTags&amp;quot;: {
        &amp;quot;Environment&amp;quot;: &amp;quot;staging&amp;quot;,
        &amp;quot;ChaosReady&amp;quot;: &amp;quot;true&amp;quot;
      },
      &amp;quot;selectionMode&amp;quot;: &amp;quot;COUNT(2)&amp;quot;
    }
  },
  &amp;quot;actions&amp;quot;: {
    &amp;quot;terminate-instances&amp;quot;: {
      &amp;quot;actionId&amp;quot;: &amp;quot;aws:ec2:terminate-instances&amp;quot;,
      &amp;quot;parameters&amp;quot;: {},
      &amp;quot;targets&amp;quot;: {
        &amp;quot;Instances&amp;quot;: &amp;quot;ec2-instances&amp;quot;
      }
    }
  },
  &amp;quot;stopConditions&amp;quot;: [
    {
      &amp;quot;source&amp;quot;: &amp;quot;aws:cloudwatch:alarm&amp;quot;,
      &amp;quot;value&amp;quot;: &amp;quot;arn:aws:cloudwatch:us-east-1:123456789012:alarm:HighErrorRate&amp;quot;
    }
  ],
  &amp;quot;roleArn&amp;quot;: &amp;quot;arn:aws:iam::123456789012:role/FISExperimentRole&amp;quot;,
  &amp;quot;tags&amp;quot;: {
    &amp;quot;Name&amp;quot;: &amp;quot;EC2-Termination-Test&amp;quot;,
    &amp;quot;Team&amp;quot;: &amp;quot;Platform&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To run this experiment:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash

# Create the experiment template
TEMPLATE_ID=$(aws fis create-experiment-template \
  --cli-input-json file://aws-fis-ec2-termination.json \
  --query &amp;#39;experimentTemplate.id&amp;#39; \
  --output text)

echo &amp;quot;Created experiment template: $TEMPLATE_ID&amp;quot;

# Start the experiment
EXPERIMENT_ID=$(aws fis start-experiment \
  --experiment-template-id &amp;quot;$TEMPLATE_ID&amp;quot; \
  --query &amp;#39;experiment.id&amp;#39; \
  --output text)

echo &amp;quot;Started experiment: $EXPERIMENT_ID&amp;quot;

# Monitor experiment status
aws fis get-experiment \
  --id &amp;quot;$EXPERIMENT_ID&amp;quot; \
  --query &amp;#39;experiment.state.status&amp;#39; \
  --output text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Examples of Chaos Experiments in AWS Services:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Amazon Aurora:&lt;/strong&gt; Simulate network latency between Aurora instances, introduce failures in replica instances, or test increased load on read/write capacity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Amazon Kinesis:&lt;/strong&gt; Simulate higher data ingestion rates to test stream scaling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Amazon EC2:&lt;/strong&gt; Test Spot Instance interruptions to verify application handling of sudden terminations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Amazon DynamoDB:&lt;/strong&gt; Deny traffic to/from regional endpoints to test failover mechanisms.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A unique challenge arises with serverless environments like AWS Lambda. You don&amp;#39;t control or access the underlying infrastructure, making traditional fault injection difficult. Here are two approaches:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Using a Library in Lambda Code:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can inject faults directly within the Lambda function using a library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import {DynamoDBClient, PutItemCommand} from &amp;#39;@aws-sdk/client-dynamodb&amp;#39;;
import {S3Client, GetObjectCommand} from &amp;#39;@aws-sdk/client-s3&amp;#39;;

// Initialize AWS SDK v3 clients
const dynamoClient = new DynamoDBClient({region: process.env.AWS_REGION});
const s3Client = new S3Client({region: process.env.AWS_REGION});

/**
 * Chaos injection library for Lambda functions
 * Supports error injection, latency injection, and custom failure scenarios
 */
class ChaosInjector {
  constructor(config = {}) {
    this.errorRate = parseFloat(config.errorRate) || 0;
    this.latencyMs = parseInt(config.latencyMs, 10) || 0;
    this.failureTypes = config.failureTypes || [&amp;#39;generic_error&amp;#39;];
    this.enabled = config.enabled !== false;
  }

  /**
   * Inject artificial latency
   */
  async injectLatency() {
    if (this.latencyMs &amp;gt; 0) {
      console.log(`[Chaos] Injecting ${this.latencyMs}ms latency`);
      await new Promise((resolve) =&amp;gt; setTimeout(resolve, this.latencyMs));
    }
  }

  /**
   * Inject random errors based on error rate
   */
  async injectError() {
    if (Math.random() &amp;lt; this.errorRate) {
      const failureType =
        this.failureTypes[Math.floor(Math.random() * this.failureTypes.length)];

      console.error(`[Chaos] Injecting failure: ${failureType}`);

      switch (failureType) {
        case &amp;#39;timeout_error&amp;#39;:
          throw new Error(&amp;#39;Chaos: Simulated timeout error&amp;#39;);
        case &amp;#39;throttle_error&amp;#39;:
          const error = new Error(&amp;#39;Chaos: Simulated throttling&amp;#39;);
          error.code = &amp;#39;ThrottlingException&amp;#39;;
          throw error;
        case &amp;#39;service_unavailable&amp;#39;:
          const unavailableError = new Error(&amp;#39;Chaos: Service unavailable&amp;#39;);
          unavailableError.statusCode = 503;
          throw unavailableError;
        default:
          throw new Error(&amp;#39;Chaos: Simulated generic failure&amp;#39;);
      }
    }
  }

  /**
   * Execute chaos injection
   */
  async inject() {
    if (!this.enabled) {
      return;
    }

    await this.injectLatency();
    await this.injectError();
  }
}

// Initialize chaos injector from environment variables
const chaos = new ChaosInjector({
  errorRate: process.env.CHAOS_ERROR_RATE || 0,
  latencyMs: process.env.CHAOS_LATENCY_MS || 0,
  failureTypes: process.env.CHAOS_FAILURE_TYPES?.split(&amp;#39;,&amp;#39;) || [
    &amp;#39;generic_error&amp;#39;,
  ],
  enabled: process.env.CHAOS_ENABLED !== &amp;#39;false&amp;#39;,
});

/**
 * Lambda handler with chaos engineering
 */
export const handler = async (event, context) =&amp;gt; {
  console.log(&amp;#39;Processing request:&amp;#39;, {requestId: context.requestId});

  try {
    // Inject chaos before processing
    await chaos.inject();

    // Your actual business logic
    const result = await processRequest(event);

    return {
      statusCode: 200,
      headers: {
        &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
        &amp;#39;X-Request-Id&amp;#39;: context.requestId,
      },
      body: JSON.stringify(result),
    };
  } catch (error) {
    console.error(&amp;#39;Error processing request:&amp;#39;, {
      error: error.message,
      stack: error.stack,
      requestId: context.requestId,
    });

    return {
      statusCode: error.statusCode || 500,
      headers: {
        &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
        &amp;#39;X-Request-Id&amp;#39;: context.requestId,
      },
      body: JSON.stringify({
        error: error.message,
        requestId: context.requestId,
      }),
    };
  }
};

/**
 * Example business logic using AWS SDK v3
 */
async function processRequest(event) {
  const {userId, action} = JSON.parse(event.body || &amp;#39;{}&amp;#39;);

  // Example: Write to DynamoDB using AWS SDK v3
  if (action === &amp;#39;save&amp;#39;) {
    const command = new PutItemCommand({
      TableName: process.env.TABLE_NAME,
      Item: {
        userId: {S: userId},
        timestamp: {N: Date.now().toString()},
        data: {S: JSON.stringify(event.body)},
      },
    });

    await dynamoClient.send(command);
  }

  // Example: Read from S3 using AWS SDK v3
  if (action === &amp;#39;fetch&amp;#39;) {
    const command = new GetObjectCommand({
      Bucket: process.env.BUCKET_NAME,
      Key: `users/${userId}/data.json`,
    });

    const response = await s3Client.send(command);
    const data = await response.Body.transformToString();
    return {data: JSON.parse(data)};
  }

  return {message: &amp;#39;Success&amp;#39;, userId, action};
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. Using a Lambda Extension:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can deploy a Lambda layer that injects failures without changing your main function code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;#!/usr/bin/env python3
&amp;quot;&amp;quot;&amp;quot;Lambda Extension for Chaos Engineering

This extension intercepts Lambda invocations and injects controlled failures
to test system resilience without modifying application code.
&amp;quot;&amp;quot;&amp;quot;

import os
import sys
import json
import random
import time
import signal
import requests
from pathlib import Path
from typing import Dict, List, Optional, Tuple
from datetime import datetime

# Lambda Extensions API endpoint
EXTENSION_API = f&amp;quot;http://{os.getenv(&amp;#39;AWS_LAMBDA_RUNTIME_API&amp;#39;)}/2020-01-01/extension&amp;quot;


class ChaosExtension:
    &amp;quot;&amp;quot;&amp;quot;Chaos injection engine for Lambda functions&amp;quot;&amp;quot;&amp;quot;

    def __init__(self):
        self.extension_id: Optional[str] = None
        self.error_rate = float(os.getenv(&amp;#39;CHAOS_ERROR_RATE&amp;#39;, &amp;#39;0.0&amp;#39;))
        self.latency_ms = int(os.getenv(&amp;#39;CHAOS_LATENCY_MS&amp;#39;, &amp;#39;0&amp;#39;))
        self.max_latency_ms = int(os.getenv(&amp;#39;CHAOS_MAX_LATENCY_MS&amp;#39;, &amp;#39;5000&amp;#39;))
        self.enabled = os.getenv(&amp;#39;CHAOS_ENABLED&amp;#39;, &amp;#39;true&amp;#39;).lower() == &amp;#39;true&amp;#39;

        try:
            self.failure_types = json.loads(
                os.getenv(&amp;#39;CHAOS_FAILURE_TYPES&amp;#39;, &amp;#39;[&amp;quot;http_error&amp;quot;]&amp;#39;)
            )
        except json.JSONDecodeError:
            self.failure_types = [&amp;#39;http_error&amp;#39;]
            print(&amp;#39;[chaos-extension] Warning: Invalid CHAOS_FAILURE_TYPES, using default&amp;#39;)

        # Validate configuration
        self._validate_config()

    def _validate_config(self) -&amp;gt; None:
        &amp;quot;&amp;quot;&amp;quot;Validate chaos configuration parameters&amp;quot;&amp;quot;&amp;quot;
        if not 0 &amp;lt;= self.error_rate &amp;lt;= 1:
            print(f&amp;#39;[chaos-extension] Warning: Invalid error_rate {self.error_rate}, clamping to [0,1]&amp;#39;)
            self.error_rate = max(0, min(1, self.error_rate))

        if self.latency_ms &amp;lt; 0:
            print(f&amp;#39;[chaos-extension] Warning: Negative latency {self.latency_ms}ms, setting to 0&amp;#39;)
            self.latency_ms = 0

        if self.latency_ms &amp;gt; self.max_latency_ms:
            print(f&amp;#39;[chaos-extension] Warning: Latency {self.latency_ms}ms exceeds max {self.max_latency_ms}ms&amp;#39;)
            self.latency_ms = self.max_latency_ms

    def register(self) -&amp;gt; str:
        &amp;quot;&amp;quot;&amp;quot;Register extension with Lambda Extensions API&amp;quot;&amp;quot;&amp;quot;
        try:
            response = requests.post(
                f&amp;#39;{EXTENSION_API}/register&amp;#39;,
                json={&amp;#39;events&amp;#39;: [&amp;#39;INVOKE&amp;#39;, &amp;#39;SHUTDOWN&amp;#39;]},
                headers={&amp;#39;Lambda-Extension-Name&amp;#39;: &amp;#39;chaos-extension&amp;#39;},
                timeout=5
            )
            response.raise_for_status()
            self.extension_id = response.headers[&amp;#39;Lambda-Extension-Identifier&amp;#39;]
            print(f&amp;#39;[chaos-extension] Registered with ID: {self.extension_id}&amp;#39;)
            return self.extension_id
        except Exception as e:
            print(f&amp;#39;[chaos-extension] Failed to register: {e}&amp;#39;)
            sys.exit(1)

    def next_event(self) -&amp;gt; Dict:
        &amp;quot;&amp;quot;&amp;quot;Wait for next Lambda event&amp;quot;&amp;quot;&amp;quot;
        try:
            response = requests.get(
                f&amp;#39;{EXTENSION_API}/event/next&amp;#39;,
                headers={&amp;#39;Lambda-Extension-Identifier&amp;#39;: self.extension_id},
                timeout=None
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            print(f&amp;#39;[chaos-extension] Error getting next event: {e}&amp;#39;)
            sys.exit(1)

    def should_inject_chaos(self) -&amp;gt; bool:
        &amp;quot;&amp;quot;&amp;quot;Determine if chaos should be injected for this invocation&amp;quot;&amp;quot;&amp;quot;
        if not self.enabled:
            return False
        return random.random() &amp;lt; self.error_rate

    def inject_latency(self) -&amp;gt; None:
        &amp;quot;&amp;quot;&amp;quot;Inject artificial latency&amp;quot;&amp;quot;&amp;quot;
        if self.latency_ms &amp;gt; 0:
            actual_latency = random.randint(
                self.latency_ms // 2,
                self.latency_ms
            )
            print(f&amp;#39;[chaos-extension] Injecting {actual_latency}ms latency&amp;#39;)
            time.sleep(actual_latency / 1000.0)

    def inject_error(self) -&amp;gt; Optional[Tuple[int, Dict]]:
        &amp;quot;&amp;quot;&amp;quot;Inject simulated error based on failure type&amp;quot;&amp;quot;&amp;quot;
        if not self.should_inject_chaos():
            return None

        failure_type = random.choice(self.failure_types)
        timestamp = datetime.utcnow().isoformat()

        print(f&amp;#39;[chaos-extension] Injecting failure: {failure_type} at {timestamp}&amp;#39;)

        error_scenarios = {
            &amp;#39;http_error&amp;#39;: (500, {
                &amp;#39;error&amp;#39;: &amp;#39;Chaos: Simulated HTTP 500 Internal Server Error&amp;#39;,
                &amp;#39;type&amp;#39;: &amp;#39;InternalServerError&amp;#39;,
                &amp;#39;timestamp&amp;#39;: timestamp
            }),
            &amp;#39;timeout&amp;#39;: (408, {
                &amp;#39;error&amp;#39;: &amp;#39;Chaos: Simulated request timeout&amp;#39;,
                &amp;#39;type&amp;#39;: &amp;#39;RequestTimeout&amp;#39;,
                &amp;#39;timestamp&amp;#39;: timestamp
            }),
            &amp;#39;throttle&amp;#39;: (429, {
                &amp;#39;error&amp;#39;: &amp;#39;Chaos: Simulated throttling&amp;#39;,
                &amp;#39;type&amp;#39;: &amp;#39;ThrottlingException&amp;#39;,
                &amp;#39;timestamp&amp;#39;: timestamp
            }),
            &amp;#39;service_unavailable&amp;#39;: (503, {
                &amp;#39;error&amp;#39;: &amp;#39;Chaos: Service temporarily unavailable&amp;#39;,
                &amp;#39;type&amp;#39;: &amp;#39;ServiceUnavailable&amp;#39;,
                &amp;#39;timestamp&amp;#39;: timestamp
            }),
            &amp;#39;bad_gateway&amp;#39;: (502, {
                &amp;#39;error&amp;#39;: &amp;#39;Chaos: Bad gateway response&amp;#39;,
                &amp;#39;type&amp;#39;: &amp;#39;BadGateway&amp;#39;,
                &amp;#39;timestamp&amp;#39;: timestamp
            })
        }

        if failure_type == &amp;#39;timeout&amp;#39;:
            # Simulate timeout with actual delay
            timeout_duration = random.randint(1, 5)
            print(f&amp;#39;[chaos-extension] Simulating {timeout_duration}s timeout&amp;#39;)
            time.sleep(timeout_duration)

        return error_scenarios.get(
            failure_type,
            (500, {&amp;#39;error&amp;#39;: &amp;#39;Chaos: Unknown failure type&amp;#39;, &amp;#39;timestamp&amp;#39;: timestamp})
        )

    def process_invoke(self, event: Dict) -&amp;gt; None:
        &amp;quot;&amp;quot;&amp;quot;Process INVOKE event&amp;quot;&amp;quot;&amp;quot;
        request_id = event.get(&amp;#39;requestId&amp;#39;, &amp;#39;unknown&amp;#39;)
        print(f&amp;#39;[chaos-extension] Processing invocation: {request_id}&amp;#39;)

        # Inject latency before function execution
        self.inject_latency()

        # Check if error should be injected
        error = self.inject_error()
        if error:
            status_code, error_body = error
            print(f&amp;#39;[chaos-extension] Chaos injected: {status_code} - {error_body[&amp;quot;error&amp;quot;]}&amp;#39;)

    def run(self) -&amp;gt; None:
        &amp;quot;&amp;quot;&amp;quot;Main extension loop&amp;quot;&amp;quot;&amp;quot;
        print(&amp;#39;[chaos-extension] Starting chaos extension&amp;#39;)
        print(f&amp;#39;[chaos-extension] Configuration:&amp;#39;)
        print(f&amp;#39;  - Enabled: {self.enabled}&amp;#39;)
        print(f&amp;#39;  - Error rate: {self.error_rate * 100:.1f}%&amp;#39;)
        print(f&amp;#39;  - Latency: {self.latency_ms}ms (max: {self.max_latency_ms}ms)&amp;#39;)
        print(f&amp;#39;  - Failure types: {self.failure_types}&amp;#39;)

        # Register extension
        self.register()

        # Main event loop
        while True:
            event = self.next_event()
            event_type = event.get(&amp;#39;eventType&amp;#39;)

            if event_type == &amp;#39;INVOKE&amp;#39;:
                self.process_invoke(event)
            elif event_type == &amp;#39;SHUTDOWN&amp;#39;:
                print(&amp;#39;[chaos-extension] Shutdown event received&amp;#39;)
                break
            else:
                print(f&amp;#39;[chaos-extension] Unknown event type: {event_type}&amp;#39;)


def signal_handler(signum, frame):
    &amp;quot;&amp;quot;&amp;quot;Handle shutdown signals gracefully&amp;quot;&amp;quot;&amp;quot;
    print(f&amp;#39;[chaos-extension] Received signal {signum}, shutting down&amp;#39;)
    sys.exit(0)


if __name__ == &amp;#39;__main__&amp;#39;:
    # Register signal handlers
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGINT, signal_handler)

    try:
        chaos = ChaosExtension()
        chaos.run()
    except Exception as e:
        print(f&amp;#39;[chaos-extension] Fatal error: {e}&amp;#39;)
        sys.exit(1)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What is Chaos Engineering? | OpenText, accessed on June 6, 2025, &lt;a href=&quot;https://www.opentext.com/what-is/chaos-engineering&quot;&gt;https://www.opentext.com/what-is/chaos-engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Chaos Engineering Tutorial: Comprehensive Guide With Best Practices - LambdaTest, accessed on June 6, 2025, &lt;a href=&quot;https://www.lambdatest.com/learning-hub/chaos-engineering-tutorial&quot;&gt;https://www.lambdatest.com/learning-hub/chaos-engineering-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Home - Chaos Monkey, accessed on June 6, 2025, &lt;a href=&quot;https://netflix.github.io/chaosmonkey/&quot;&gt;https://netflix.github.io/chaosmonkey/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Netflix/chaosmonkey: Chaos Monkey is a resiliency tool ... - GitHub, accessed on June 6, 2025, &lt;a href=&quot;https://github.com/Netflix/chaosmonkey&quot;&gt;https://github.com/Netflix/chaosmonkey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Chaos Engineering | Gremlin, accessed on June 6, 2025, &lt;a href=&quot;https://www.gremlin.com/product/chaos-engineering&quot;&gt;https://www.gremlin.com/product/chaos-engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Comparing Chaos Engineering tools - Gremlin, accessed on June 6, 2025, &lt;a href=&quot;https://www.gremlin.com/community/tutorials/chaos-engineering-tools-comparison&quot;&gt;https://www.gremlin.com/community/tutorials/chaos-engineering-tools-comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Chaos Monkey vs Gremlin vs Pumba - Bwiza Charlotte, accessed on June 6, 2025, &lt;a href=&quot;https://bwiza.hashnode.dev/chaos-monkey-vs-gremlin-vs-pumba&quot;&gt;https://bwiza.hashnode.dev/chaos-monkey-vs-gremlin-vs-pumba&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS chaos engineering tools: PwC, accessed on June 6, 2025, &lt;a href=&quot;https://www.pwc.com/us/en/technology/alliances/library/aws-chaos-engineering.html&quot;&gt;https://www.pwc.com/us/en/technology/alliances/library/aws-chaos-engineering.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Introduction to Chaos Engineering in Serverless Architectures - Ran The Builder, accessed on June 6, 2025, &lt;a href=&quot;https://www.ranthebuilder.cloud/post/introduction-to-chaos-engineering-serverless&quot;&gt;https://www.ranthebuilder.cloud/post/introduction-to-chaos-engineering-serverless&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;information system resilience - Glossary - NIST CSRC, accessed on June 6, 2025, &lt;a href=&quot;https://csrc.nist.gov/glossary/term/information_system_resilience&quot;&gt;https://csrc.nist.gov/glossary/term/information_system_resilience&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Chaos Engineering Explained: Core Principles and ... - Distant Job, accessed on June 6, 2025, &lt;a href=&quot;https://distantjob.com/blog/chaos-engineering/&quot;&gt;https://distantjob.com/blog/chaos-engineering/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Types of chaos experiments - Fork My Brain, accessed on June 6, 2025, &lt;a href=&quot;https://notes.nicolevanderhoeven.com/Types+of+chaos+experiments&quot;&gt;https://notes.nicolevanderhoeven.com/Types+of+chaos+experiments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gremlin vs Harness CE: Chaos Engineering Comparison, accessed on June 6, 2025, &lt;a href=&quot;https://www.harness.io/comparison-guide/gremlin-vs-harness&quot;&gt;https://www.harness.io/comparison-guide/gremlin-vs-harness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I&amp;#39;m Kolton Andrus, Ask Me Anything about Chaos Engineering - Atlassian Community, accessed on June 6, 2025, &lt;a href=&quot;https://community.atlassian.com/forums/Jira-questions/I-m-Kolton-Andrus-Ask-Me-Anything-about-Chaos-Engineering/qaq-p/1342117&quot;&gt;https://community.atlassian.com/forums/Jira-questions/I-m-Kolton-Andrus-Ask-Me-Anything-about-Chaos-Engineering/qaq-p/1342117&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Chaos Engineering with Chaos Mesh and vCluster: Testing Close to ..., accessed on June 6, 2025, &lt;a href=&quot;https://www.loft.sh/blog/chaos-mesh-with-vcluster&quot;&gt;https://www.loft.sh/blog/chaos-mesh-with-vcluster&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Chaos Engineering</category><category>System Reliability</category><category>DevOps</category><category>Site Reliability Engineering</category><category>Testing</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0093-chaos-engineering-resiliency-testing-monkey-gremlin/hero.jpg" length="0" type="image/jpeg"/></item><item><title>What&apos;s the Deal with Shift-Left Security, and Why Should You Care?</title><link>https://mkabumattar.com/blog/post/shift-left-security-sast-dast-sca-cicd/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/shift-left-security-sast-dast-sca-cicd/</guid><description>Learn how to implement shift-left security by integrating SAST, DAST, and SCA into your CI/CD pipeline. Enhance application security, reduce costs, and accelerate development with practical guidance and tool examples like SonarQube, Trivy, and OWASP ZAP.</description><pubDate>Sat, 24 Jan 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let&amp;#39;s be honest: in today&amp;#39;s software world, security can&amp;#39;t be an afterthought. If you&amp;#39;re still waiting until the end of your development cycle to think about vulnerabilities, you&amp;#39;re doing it wrong. That&amp;#39;s where &lt;strong&gt;shift-left security&lt;/strong&gt; comes in. Instead of treating security like a final checkpoint before release, we&amp;#39;re moving it way earlier in the process, right from the start. Think of it as catching problems before they become problems.&lt;/p&gt;
&lt;p&gt;This approach fits perfectly with DevOps and DevSecOps practices. You&amp;#39;re already automating things and working cross-functionally, so why not bake security into that workflow? When you start thinking about security during the planning phase (yes, that early), you build stronger, more resilient applications. Developers catch issues when they&amp;#39;re still easy and cheap to fix. No more panic-mode security patches right before launch. &lt;strong&gt;Shift-left security&lt;/strong&gt; means you&amp;#39;re proactive instead of reactive, and that saves you time, money, and a ton of headaches.&lt;/p&gt;
&lt;p&gt;So why does this matter so much? Let&amp;#39;s break it down. First, it&amp;#39;s way cheaper to fix a security bug during development than in production. We&amp;#39;re talking orders of magnitude cheaper. Second, when security checks run alongside your normal development workflow, you actually ship faster because you&amp;#39;re not scrambling at the last minute. Third, applications built with security in mind from day one are just more secure, period. They&amp;#39;re harder to exploit and less likely to leak data.&lt;/p&gt;
&lt;p&gt;But there&amp;#39;s more. &lt;strong&gt;Shift-left security&lt;/strong&gt; gets your dev, security, and ops teams actually talking to each other. Everyone understands the security requirements from the beginning, and developers become more security-aware over time. This approach also makes compliance easier (who doesn&amp;#39;t want that?) and builds trust with your users. Bottom line: you catch risks early, reduce technical debt, ship faster, and spend less time fixing broken things.&lt;/p&gt;
&lt;h2&gt;SAST, DAST, SCA: Your Early Warning System&lt;/h2&gt;
&lt;h3&gt;How Can SAST Help You Find Problems Early On?&lt;/h3&gt;
&lt;p&gt;Static Application Security Testing (&lt;strong&gt;SAST&lt;/strong&gt;) is your first line of defense in shift-left security. Think of it as a spell-checker, but for security vulnerabilities. &lt;strong&gt;SAST&lt;/strong&gt; tools analyze your source code without actually running it, looking for potential security issues. This is what we call &amp;quot;white box&amp;quot; testing because the tool can see everything inside your application.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how it works: the tool parses your code to understand its structure, then analyzes it to understand what it does and how different parts connect. It&amp;#39;s looking for patterns that match known vulnerabilities and bad coding practices. &lt;strong&gt;SAST&lt;/strong&gt; tools also track data flow through your application to spot places where untrusted input could cause problems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SAST&lt;/strong&gt; catches a wide range of issues: SQL injection, Cross-Site Scripting (XSS), buffer overflows, hardcoded secrets, weak cryptography, poor error handling, dead code, code duplication, and resource leaks. The best part? It gives you immediate feedback. You get the exact file, location, and line number where the problem is, plus guidance on how to fix it.&lt;/p&gt;
&lt;p&gt;You can integrate &lt;strong&gt;SAST&lt;/strong&gt; directly into your IDE so developers see issues as they code, or run it in your CI/CD pipeline for automated checks. It&amp;#39;s scalable, repeatable, and can even analyze compiled code like binaries and bytecode. By catching vulnerabilities before they reach production, &lt;strong&gt;SAST&lt;/strong&gt; makes your applications more secure and helps developers learn to write better code.&lt;/p&gt;
&lt;h3&gt;What&amp;#39;s DAST, and Why Is Testing Running Applications So Important?&lt;/h3&gt;
&lt;p&gt;Dynamic Application Security Testing (&lt;strong&gt;DAST&lt;/strong&gt;) takes a different approach. Instead of analyzing static code, &lt;strong&gt;DAST&lt;/strong&gt; tests your running application by simulating real attacks. This is &amp;quot;black box&amp;quot; testing because the tool doesn&amp;#39;t know anything about your application&amp;#39;s internals. It&amp;#39;s testing from an attacker&amp;#39;s perspective, which is exactly what you want.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DAST&lt;/strong&gt; finds issues that only show up at runtime, things &lt;strong&gt;SAST&lt;/strong&gt; can&amp;#39;t catch. It tests how your app handles requests and responses, how it interacts with other services, how it manages sessions and authentication. You get a real-world view of your security posture. &lt;strong&gt;DAST&lt;/strong&gt; excels at finding input validation issues, server misconfigurations, and authentication bypasses. It can test your entire application flow, including complex multi-step processes and business logic vulnerabilities. It&amp;#39;s also perfect for testing third-party applications where you don&amp;#39;t have source code access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DAST&lt;/strong&gt; tools launch automated attacks (SQL injection, XSS, etc.) and watch how your app responds. They generate detailed reports with actionable findings and remediation guidance. You can integrate &lt;strong&gt;DAST&lt;/strong&gt; into your CI/CD pipeline for continuous testing, run it against staging environments, or even use it on production (carefully). It helps you prioritize fixes based on actual risk and is essential for compliance requirements. Since it tests the running app, &lt;strong&gt;DAST&lt;/strong&gt; catches runtime issues and client-side vulnerabilities that static analysis misses.&lt;/p&gt;
&lt;h3&gt;What&amp;#39;s SCA, and Why Should You Keep an Eye on Your Dependencies?&lt;/h3&gt;
&lt;p&gt;Software Composition Analysis (&lt;strong&gt;SCA&lt;/strong&gt;) is your dependency watchdog. Modern applications use tons of open-source libraries and third-party components. &lt;strong&gt;SCA&lt;/strong&gt; tools automatically discover all these dependencies by scanning package managers, manifest files, source code, binaries, and container images. They create a Software Bill of Materials (SBOM), basically an inventory of everything your app depends on. Then they cross-reference this against vulnerability databases like the National Vulnerability Database (NVD) to flag any known security issues.&lt;/p&gt;
&lt;p&gt;Why does this matter? Because open-source components come with licensing requirements and security risks that are hard to track manually. &lt;strong&gt;SCA&lt;/strong&gt; helps you manage these risks by identifying vulnerable dependencies, ensuring license compliance, and monitoring your software supply chain for malicious or compromised packages. It also flags outdated components and gives you visibility into your entire dependency tree. In the DevSecOps world, &lt;strong&gt;SCA&lt;/strong&gt; is essential for shift-left security.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SCA&lt;/strong&gt; tools identify vulnerabilities and recommend fixes or updates. Some can assess the health of open-source projects. They automate dependency scanning and can alert you or even block builds if they find policy violations. Many integrate directly into your IDE to warn developers as they add new packages. &lt;strong&gt;SCA&lt;/strong&gt; scans aren&amp;#39;t limited to your code; they also check your cloud infrastructure and runtime environments. They help you manage SBOMs, track transitive dependencies (the dependencies of your dependencies), and meet compliance requirements.&lt;/p&gt;
&lt;h2&gt;Making Security a Part of Your Pipeline: Integrating SAST/DAST/SCA in CI/CD&lt;/h2&gt;
&lt;h3&gt;How Can You Integrate SAST into Your CI/CD Workflow?&lt;/h3&gt;
&lt;p&gt;Integrating &lt;strong&gt;SAST&lt;/strong&gt; into your CI/CD pipeline is crucial for catching vulnerable code before it reaches production. This automates security checks with every code change, giving developers immediate feedback so they can fix issues quickly.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how to make it work. Start by defining your security requirements clearly. Pick a &lt;strong&gt;SAST&lt;/strong&gt; tool that supports your programming languages and tech stack. Popular options include &lt;strong&gt;SonarQube&lt;/strong&gt;, Fortify, Checkmarx, and Semgrep. Connect it to your version control system (like Git) so scans trigger automatically on code changes. Configure the tool for your specific needs to reduce false positives and improve accuracy. Then integrate it into your CI/CD pipeline using Jenkins, GitLab CI, GitHub Actions, or Azure Pipelines.&lt;/p&gt;
&lt;p&gt;Run an initial scan of your existing codebase to establish a baseline. Connect the findings to your issue tracking system (like Jira) so developers get notified immediately. Many teams configure their pipeline to fail builds if critical security issues are detected. Here&amp;#39;s a practical example using GitHub Actions with SonarQube:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: SAST Security Scan

# Security: Restrict workflow triggers to prevent unauthorized runs
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  workflow_dispatch: # Allow manual triggers for security audits

# Security: Define minimum permissions (OIDC best practice)
permissions:
  contents: read
  security-events: write
  pull-requests: write

jobs:
  validate-inputs:
    name: Validate Configuration
    runs-on: ubuntu-latest
    steps:
      # Security: Validate required secrets are present
      - name: Validate Required Secrets
        run: |
          set -euo pipefail  # Exit on error, undefined vars, pipe failures

          if [ -z &amp;quot;${{ secrets.SONAR_TOKEN }}&amp;quot; ]; then
            echo &amp;quot;::error::SONAR_TOKEN secret is not configured&amp;quot;
            exit 1
          fi

          if [ -z &amp;quot;${{ secrets.SONAR_HOST_URL }}&amp;quot; ]; then
            echo &amp;quot;::error::SONAR_HOST_URL secret is not configured&amp;quot;
            exit 1
          fi

          echo &amp;quot;✓ All required secrets are configured&amp;quot;

  sonarqube:
    name: SonarQube SAST Analysis
    runs-on: ubuntu-latest
    needs: validate-inputs

    # Security: Set timeout to prevent resource exhaustion
    timeout-minutes: 30

    steps:
      # Security: Use specific version tags, not @latest
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Required for blame information
          persist-credentials: false # Security: Don&amp;#39;t persist Git credentials

      # Security: Use specific LTS Java version
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: &amp;#39;17&amp;#39;
          distribution: &amp;#39;temurin&amp;#39;
          cache: &amp;#39;maven&amp;#39; # Built-in Maven cache

      # Security: Verify Maven wrapper integrity
      - name: Validate Maven Wrapper
        run: |
          set -euo pipefail

          if [ -f &amp;quot;mvnw&amp;quot; ]; then
            # Check if Maven wrapper jar exists and verify checksum
            if [ ! -f &amp;quot;.mvn/wrapper/maven-wrapper.jar&amp;quot; ]; then
              echo &amp;quot;::error::Maven wrapper jar not found&amp;quot;
              exit 1
            fi
            echo &amp;quot;✓ Maven wrapper validated&amp;quot;
          fi

      # Security: Run dependency vulnerability check before analysis
      - name: Check Dependencies
        run: |
          set -euo pipefail
          mvn dependency:tree -DoutputFile=dependency-tree.txt
          mvn org.owasp:dependency-check-maven:check \
            -DfailBuildOnCVSS=7 \
            -DsuppressionFile=dependency-check-suppressions.xml || true

      # Security: Run SonarQube with strict settings
      - name: Run SonarQube Analysis
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
          # Security: Prevent token leakage in logs
          SONAR_SCANNER_OPTS: &amp;#39;-Dsonar.log.level=INFO&amp;#39;
        run: |
          set -euo pipefail

          # Validate URL format (prevent injection)
          if ! echo &amp;quot;$SONAR_HOST_URL&amp;quot; | grep -E &amp;#39;^https?://[a-zA-Z0-9.-]+&amp;#39;; then
            echo &amp;quot;::error::Invalid SONAR_HOST_URL format&amp;quot;
            exit 1
          fi

          # Run analysis with security-focused settings
          mvn clean verify sonar:sonar \
            -Dsonar.projectKey=my-project \
            -Dsonar.qualitygate.wait=true \
            -Dsonar.qualitygate.timeout=300 \
            -Dsonar.exclusions=&amp;quot;**/test/**,**/node_modules/**&amp;quot; \
            -Dsonar.coverage.exclusions=&amp;quot;**/test/**&amp;quot; \
            -B  # Batch mode for CI

      # Security: Verify quality gate status
      - name: Check Quality Gate Status
        if: always()
        run: |
          set -euo pipefail
          echo &amp;quot;✓ SonarQube analysis completed&amp;quot;
          echo &amp;quot;View detailed report at: ${{ secrets.SONAR_HOST_URL }}&amp;quot;

      # Security: Upload analysis artifacts (sanitized)
      - name: Upload Analysis Report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: sonarqube-analysis
          path: |
            target/sonar/report-task.txt
            dependency-tree.txt
          retention-days: 30
          if-no-files-found: warn

      # Security: Notify on failure
      - name: Notify on Failure
        if: failure()
        run: |
          echo &amp;quot;::error::SAST scan failed - review security findings before merge&amp;quot;
          exit 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Platforms like GitLab often have built-in CI/CD templates that make SAST integration even easier. Use incremental analysis features when available to speed up scans by only checking changed code. Some &lt;strong&gt;SAST&lt;/strong&gt; tools include training features to help developers learn secure coding practices. Keep your tools updated and regularly review your security policies. Create dashboards to visualize SAST results and track security trends over time.&lt;/p&gt;
&lt;p&gt;The key is making &lt;strong&gt;SAST&lt;/strong&gt; work smoothly with CI/CD so everyone on the team takes ownership of security, and your tool needs to support the languages you&amp;#39;re actually using.&lt;/p&gt;
&lt;h3&gt;What&amp;#39;s the Best Way to Add DAST to Your CI/CD Pipeline?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;DAST&lt;/strong&gt; is essential for finding security vulnerabilities by simulating real attacks on your running application. Unlike &lt;strong&gt;SAST&lt;/strong&gt;, you need your app deployed to a test or staging environment before &lt;strong&gt;DAST&lt;/strong&gt; can do its thing.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how to make it work. Automate &lt;strong&gt;DAST&lt;/strong&gt; scans to run with every build or deployment. Choose tools designed for your specific application types (web apps, APIs, etc.). Popular options include &lt;strong&gt;OWASP ZAP&lt;/strong&gt;, Acunetix, Burp Suite, and GitLab DAST. These integrate with CI/CD platforms like GitLab, CircleCI, and Azure DevOps through plugins or extensions.&lt;/p&gt;
&lt;p&gt;For authenticated applications, configure your &lt;strong&gt;DAST&lt;/strong&gt; tool with proper credentials so it can test protected areas. After scans complete, review the reports carefully, prioritize findings, and use the insights to improve your security. Run &lt;strong&gt;DAST&lt;/strong&gt; early and often. Connect it to your bug tracking system for smoother remediation workflows.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a practical example using OWASP ZAP in a GitLab CI pipeline:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Security: Define execution stages
stages:
  - validate
  - deploy
  - security-scan
  - report

# Security: Global variables with safe defaults
variables:
  # Prevent credential leakage in logs
  GIT_STRATEGY: fetch
  GIT_DEPTH: 1
  # Security: Set scan timeout
  ZAP_SCAN_TIMEOUT: &amp;#39;10&amp;#39;
  # Security: Define acceptable risk threshold
  ZAP_FAIL_ON_SEVERITY: &amp;#39;HIGH&amp;#39;

# Security: Validate configuration before deployment
validate_config:
  stage: validate
  image: alpine:latest
  script:
    - |
      set -euo pipefail

      # Validate required variables
      if [ -z &amp;quot;${STAGING_URL:-}&amp;quot; ]; then
        echo &amp;quot;ERROR: STAGING_URL not configured&amp;quot;
        exit 1
      fi

      # Security: Validate URL format (prevent injection)
      if ! echo &amp;quot;$STAGING_URL&amp;quot; | grep -E &amp;#39;^https://[a-zA-Z0-9.-]+&amp;#39;; then
        echo &amp;quot;ERROR: STAGING_URL must use HTTPS and valid hostname&amp;quot;
        exit 1
      fi

      # Security: Check for secure protocol
      if echo &amp;quot;$STAGING_URL&amp;quot; | grep -q &amp;#39;^http://&amp;#39;; then
        echo &amp;quot;WARNING: Non-HTTPS URL detected - security scan may be unreliable&amp;quot;
      fi

      echo &amp;quot;✓ Configuration validated successfully&amp;quot;
  only:
    - branches

# Security: Deploy to isolated staging environment
deploy_staging:
  stage: deploy
  image: alpine:latest
  needs: [validate_config]

  # Security: Set deployment timeout
  timeout: 15 minutes

  script:
    - |
      set -euo pipefail

      echo &amp;quot;Deploying to staging environment...&amp;quot;

      # Security: Validate deployment script exists and is executable
      if [ ! -f &amp;quot;./deploy-staging.sh&amp;quot; ]; then
        echo &amp;quot;ERROR: Deployment script not found&amp;quot;
        exit 1
      fi

      if [ ! -x &amp;quot;./deploy-staging.sh&amp;quot; ]; then
        echo &amp;quot;ERROR: Deployment script is not executable&amp;quot;
        exit 1
      fi

      # Security: Run deployment with strict error handling
      ./deploy-staging.sh

      # Security: Verify deployment health
      echo &amp;quot;Waiting for application to be ready...&amp;quot;
      for i in {1..30}; do
        if wget --spider --timeout=5 &amp;quot;${STAGING_URL}/health&amp;quot; 2&amp;gt;/dev/null; then
          echo &amp;quot;✓ Application is healthy&amp;quot;
          exit 0
        fi
        sleep 10
      done

      echo &amp;quot;ERROR: Application health check failed&amp;quot;
      exit 1

  environment:
    name: staging
    url: $STAGING_URL
    on_stop: cleanup_staging

  only:
    - branches

# Security: Run DAST scan with comprehensive checks
dast_scan:
  stage: security-scan
  # Security: Use specific version tag
  image: owasp/zap2docker-stable:latest
  needs: [deploy_staging]

  # Security: Set scan timeout
  timeout: 30 minutes

  variables:
    # Security: Restrict ZAP memory usage
    ZAP_JAVA_OPTS: &amp;#39;-Xmx2048m&amp;#39;

  script:
    - |
      set -euo pipefail

      # Security: Create working directory with proper permissions
      mkdir -p /zap/wrk
      chmod 700 /zap/wrk

      # Security: Validate target URL
      TARGET_URL=&amp;quot;${STAGING_URL}&amp;quot;
      if ! echo &amp;quot;$TARGET_URL&amp;quot; | grep -E &amp;#39;^https://[a-zA-Z0-9.-]+&amp;#39;; then
        echo &amp;quot;ERROR: Invalid target URL format&amp;quot;
        exit 1
      fi

      echo &amp;quot;Starting DAST scan on: $TARGET_URL&amp;quot;

      # Security: Create ZAP configuration with safe settings
      cat &amp;gt; /zap/wrk/zap-config.conf &amp;lt;&amp;lt; &amp;#39;EOF&amp;#39;
      # Rate limiting to prevent DoS on target
      rules.config.script.passive.enabled=true
      scanner.threadPerHost=2
      connection.timeoutInSecs=30
      EOF

      # Security: Run baseline scan with strict settings
      zap-baseline.py \
        -t &amp;quot;$TARGET_URL&amp;quot; \
        -c /zap/wrk/zap-config.conf \
        -r dast-report.html \
        -w dast-report.md \
        -J dast-report.json \
        -x dast-report.xml \
        -d \
        -T &amp;quot;${ZAP_SCAN_TIMEOUT}&amp;quot; \
        -z &amp;quot;-config api.disablekey=true&amp;quot; || SCAN_EXIT_CODE=$?

      # Security: Parse results and determine severity
      if [ -f &amp;quot;dast-report.json&amp;quot; ]; then
        HIGH_COUNT=$(jq &amp;#39;[.site[].alerts[] | select(.riskdesc | startswith(&amp;quot;High&amp;quot;))] | length&amp;#39; dast-report.json || echo &amp;quot;0&amp;quot;)
        MEDIUM_COUNT=$(jq &amp;#39;[.site[].alerts[] | select(.riskdesc | startswith(&amp;quot;Medium&amp;quot;))] | length&amp;#39; dast-report.json || echo &amp;quot;0&amp;quot;)

        echo &amp;quot;Security Scan Results:&amp;quot;
        echo &amp;quot;  High Severity Issues: $HIGH_COUNT&amp;quot;
        echo &amp;quot;  Medium Severity Issues: $MEDIUM_COUNT&amp;quot;

        # Security: Fail on high severity issues
        if [ &amp;quot;$HIGH_COUNT&amp;quot; -gt 0 ]; then
          echo &amp;quot;ERROR: High severity vulnerabilities detected!&amp;quot;
          exit 1
        fi
      fi

      echo &amp;quot;✓ DAST scan completed successfully&amp;quot;

  # Security: Preserve scan results for audit
  artifacts:
    when: always
    paths:
      - dast-report.html
      - dast-report.json
      - dast-report.xml
      - dast-report.md
    reports:
      junit: dast-report.xml
    expire_in: 90 days

  # Security: Don&amp;#39;t allow failure in production pipeline
  allow_failure: false

  only:
    - branches

# Security: Cleanup staging environment
cleanup_staging:
  stage: report
  image: alpine:latest
  script:
    - echo &amp;quot;Cleaning up staging environment...&amp;quot;
    - ./cleanup-staging.sh || true
  when: manual
  environment:
    name: staging
    action: stop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For faster feedback, use &lt;strong&gt;OWASP ZAP&lt;/strong&gt;&amp;#39;s baseline scan mode for quick passive checks. Focus scans on specific parts of your application to speed things up. For API testing, &lt;strong&gt;OWASP ZAP&lt;/strong&gt; works great for checking OWASP Top 10 API Security Risks. Use &lt;strong&gt;DAST&lt;/strong&gt; alongside &lt;strong&gt;SAST&lt;/strong&gt; for comprehensive coverage.&lt;/p&gt;
&lt;p&gt;Some teams even run &lt;strong&gt;DAST&lt;/strong&gt; scans on production in non-intrusive mode to catch issues in the real environment. The key is automating these attacks so you find vulnerabilities before the bad guys do.&lt;/p&gt;
&lt;h2&gt;Integrating SCA into Your CI/CD: Ensuring Secure Dependencies&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;SCA&lt;/strong&gt; in your CI/CD pipeline ensures your dependencies stay secure. These tools discover open-source components and third-party libraries, then flag known vulnerabilities and licensing issues.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the approach: automate scans and generate detailed reports. Trigger scans at scheduled intervals or on specific events like new commits. Running &lt;strong&gt;SCA&lt;/strong&gt; directly in your CI/CD pipeline gives you continuous monitoring. Popular tools include &lt;strong&gt;OWASP Dependency-Check&lt;/strong&gt;, Snyk, Black Duck, and Trivy. Some platforms offer combined solutions like Mend CLI and Veracode SCA.&lt;/p&gt;
&lt;p&gt;Scan early in your pipeline to catch vulnerable dependencies before they cause problems. &lt;strong&gt;SCA&lt;/strong&gt; tools generate SBOMs (Software Bill of Materials), giving you a complete inventory of your components. Use automated policies to block risky dependencies. Integrate with IDEs and version control systems for real-time developer alerts.&lt;/p&gt;
&lt;p&gt;Look for tools that continuously discover and prioritize vulnerabilities by risk so your team can focus on what matters most. They should constantly monitor for newly reported vulnerabilities and automatically check license compliance. Configure your pipeline to fail builds that don&amp;#39;t meet your security policies and track vulnerability trends across builds.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a practical example using Trivy in GitHub Actions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: SCA Dependency Scan

# Security: Controlled trigger conditions
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened]
  schedule:
    # Security: Daily scan at 2 AM UTC for new CVEs
    - cron: &amp;#39;0 2 * * *&amp;#39;
  workflow_dispatch: # Manual security audits

# Security: Minimal required permissions
permissions:
  contents: read
  security-events: write
  pull-requests: write
  issues: write

jobs:
  validate-environment:
    name: Validate Scan Environment
    runs-on: ubuntu-latest
    timeout-minutes: 5

    steps:
      - name: Validate Configuration
        run: |
          set -euo pipefail

          echo &amp;quot;Validating scan environment...&amp;quot;

          # Security: Check runner environment
          if [ -z &amp;quot;${GITHUB_WORKSPACE:-}&amp;quot; ]; then
            echo &amp;quot;::error::Invalid GitHub workspace&amp;quot;
            exit 1
          fi

          # Security: Verify Trivy is available
          echo &amp;quot;✓ Environment validated&amp;quot;

  trivy_filesystem_scan:
    name: Scan Dependencies (Filesystem)
    runs-on: ubuntu-latest
    needs: validate-environment
    timeout-minutes: 20

    steps:
      # Security: Checkout with minimal permissions
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          persist-credentials: false
          fetch-depth: 1

      # Security: Use specific Trivy version for reproducibility
      - name: Run Trivy Vulnerability Scanner
        uses: aquasecurity/trivy-action@0.16.1
        with:
          scan-type: &amp;#39;fs&amp;#39;
          scan-ref: &amp;#39;.&amp;#39;
          format: &amp;#39;sarif&amp;#39;
          output: &amp;#39;trivy-results.sarif&amp;#39;
          severity: &amp;#39;CRITICAL,HIGH&amp;#39;
          # Security: Scan for vulnerabilities and misconfigurations
          scanners: &amp;#39;vuln,secret,config&amp;#39;
          # Security: Include license checks
          license-full: true
          # Security: Timeout protection
          timeout: &amp;#39;10m&amp;#39;
        env:
          # Security: Disable analytics/telemetry
          TRIVY_DISABLE_VEX_NOTICE: &amp;#39;true&amp;#39;

      # Security: Validate SARIF output before upload
      - name: Validate SARIF Report
        run: |
          set -euo pipefail

          if [ ! -f &amp;quot;trivy-results.sarif&amp;quot; ]; then
            echo &amp;quot;::error::SARIF report not generated&amp;quot;
            exit 1
          fi

          # Check if file is valid JSON
          if ! jq empty trivy-results.sarif 2&amp;gt;/dev/null; then
            echo &amp;quot;::error::Invalid SARIF format&amp;quot;
            exit 1
          fi

          # Count vulnerabilities
          VULN_COUNT=$(jq &amp;#39;[.runs[].results[]] | length&amp;#39; trivy-results.sarif)
          echo &amp;quot;Found $VULN_COUNT security findings&amp;quot;

      # Security: Upload to GitHub Security tab
      - name: Upload to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: &amp;#39;trivy-results.sarif&amp;#39;
          category: &amp;#39;trivy-filesystem&amp;#39;

      # Security: Generate human-readable report
      - name: Generate Detailed Report
        uses: aquasecurity/trivy-action@0.16.1
        with:
          scan-type: &amp;#39;fs&amp;#39;
          scan-ref: &amp;#39;.&amp;#39;
          format: &amp;#39;table&amp;#39;
          output: &amp;#39;trivy-report.txt&amp;#39;
          severity: &amp;#39;CRITICAL,HIGH,MEDIUM&amp;#39;
          scanners: &amp;#39;vuln,secret,config&amp;#39;

      # Security: Create sanitized report for artifact upload
      - name: Sanitize Report
        if: always()
        run: |
          set -euo pipefail

          # Remove potential secrets from report
          if [ -f &amp;quot;trivy-report.txt&amp;quot; ]; then
            # Mask potential sensitive patterns
            sed -i &amp;#39;s/[A-Za-z0-9]\{32,\}/***REDACTED***/g&amp;#39; trivy-report.txt
          fi

      # Security: Upload artifacts with retention policy
      - name: Upload Scan Results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: trivy-scan-results-${{ github.run_number }}
          path: |
            trivy-results.sarif
            trivy-report.txt
          retention-days: 90
          if-no-files-found: error

      # Security: Enforce vulnerability threshold
      - name: Check Vulnerability Threshold
        uses: aquasecurity/trivy-action@0.16.1
        with:
          scan-type: &amp;#39;fs&amp;#39;
          scan-ref: &amp;#39;.&amp;#39;
          exit-code: &amp;#39;1&amp;#39;
          severity: &amp;#39;CRITICAL,HIGH&amp;#39;
          scanners: &amp;#39;vuln&amp;#39;
          # Security: Ignore unfixed vulnerabilities in dev dependencies
          ignore-unfixed: true

      # Security: Create GitHub issue for critical findings
      - name: Create Security Issue
        if: failure()
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require(&amp;#39;fs&amp;#39;);
            const report = fs.readFileSync(&amp;#39;trivy-report.txt&amp;#39;, &amp;#39;utf8&amp;#39;);

            const issue = await github.rest.issues.create({
              owner: context.repo.owner,
              repo: context.repo.repo,
              title: `🚨 Security: Critical vulnerabilities detected in ${context.ref}`,
              body: `## Security Scan Results\n\n` +
                    `**Workflow Run:** ${context.runId}\n` +
                    `**Commit:** ${context.sha}\n\n` +
                    `### Findings\n\n\`\`\`\n${report}\n\`\`\`\n\n` +
                    `**Action Required:** Review and remediate these vulnerabilities before merging.`,
              labels: [&amp;#39;security&amp;#39;, &amp;#39;vulnerability&amp;#39;]
            });

            console.log(`Created issue #${issue.data.number}`);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This scans your filesystem for vulnerable dependencies, uploads findings to GitHub Security tab, and fails the build if critical or high-severity vulnerabilities are found. You can also scan Docker images:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Security: Build Docker image with security controls
- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3
  with:
    # Security: Enable BuildKit security features
    driver-opts: |
      image=moby/buildkit:latest
      network=host

# Security: Build with security scanner integration
- name: Build Docker Image
  run: |
    set -euo pipefail

    # Security: Validate Dockerfile exists
    if [ ! -f &amp;quot;Dockerfile&amp;quot; ]; then
      echo &amp;quot;::error::Dockerfile not found&amp;quot;
      exit 1
    fi

    # Security: Scan Dockerfile for issues before building
    docker run --rm -i hadolint/hadolint &amp;lt; Dockerfile || true

    # Security: Build with security labels and no cache for reproducibility
    docker build \
      --no-cache \
      --pull \
      --label &amp;quot;org.opencontainers.image.created=$(date -u +&amp;#39;%Y-%m-%dT%H:%M:%SZ&amp;#39;)&amp;quot; \
      --label &amp;quot;org.opencontainers.image.revision=${{ github.sha }}&amp;quot; \
      --label &amp;quot;org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}&amp;quot; \
      -t myapp:${{ github.sha }} \
      -t myapp:scan-candidate \
      .

    echo &amp;quot;✓ Docker image built successfully&amp;quot;

# Security: Comprehensive image vulnerability scan
- name: Scan Docker Image for Vulnerabilities
  uses: aquasecurity/trivy-action@0.16.1
  with:
    image-ref: &amp;#39;myapp:${{ github.sha }}&amp;#39;
    format: &amp;#39;sarif&amp;#39;
    output: &amp;#39;trivy-image-results.sarif&amp;#39;
    severity: &amp;#39;CRITICAL,HIGH,MEDIUM&amp;#39;
    # Security: Scan all layers and dependencies
    scanners: &amp;#39;vuln,secret,config&amp;#39;
    # Security: Include OS packages and application dependencies
    vuln-type: &amp;#39;os,library&amp;#39;
    # Security: Timeout protection
    timeout: &amp;#39;15m&amp;#39;
  env:
    TRIVY_DISABLE_VEX_NOTICE: &amp;#39;true&amp;#39;

# Security: Validate and upload results
- name: Upload Image Scan Results
  uses: github/codeql-action/upload-sarif@v3
  if: always()
  with:
    sarif_file: &amp;#39;trivy-image-results.sarif&amp;#39;
    category: &amp;#39;trivy-container&amp;#39;

# Security: Generate SBOM for supply chain security
- name: Generate SBOM
  run: |
    set -euo pipefail

    docker run --rm \
      -v /var/run/docker.sock:/var/run/docker.sock \
      aquasec/trivy image \
      --format cyclonedx \
      --output sbom.json \
      myapp:${{ github.sha }}

    # Validate SBOM is valid JSON
    if ! jq empty sbom.json 2&amp;gt;/dev/null; then
      echo &amp;quot;::error::Invalid SBOM format&amp;quot;
      exit 1
    fi

    echo &amp;quot;✓ SBOM generated successfully&amp;quot;

# Security: Fail build on critical vulnerabilities
- name: Check Image Security Threshold
  run: |
    set -euo pipefail

    # Run scan with exit code check
    docker run --rm \
      -v /var/run/docker.sock:/var/run/docker.sock \
      aquasec/trivy image \
      --exit-code 1 \
      --severity CRITICAL,HIGH \
      --ignore-unfixed \
      myapp:${{ github.sha }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The best &lt;strong&gt;SCA&lt;/strong&gt; tools provide actionable remediation advice, not just a list of problems. They tell you exactly which version to upgrade to or how to work around the issue.&lt;/p&gt;
&lt;h2&gt;Putting It All Together: Tools in Action&lt;/h2&gt;
&lt;h3&gt;How Can SonarQube Help with Shift-Left in CI/CD?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;SonarQube&lt;/strong&gt; is one of the most popular open-source platforms for continuous code quality and security analysis. It supports over 20 programming languages out of the box (with more available via plugins). &lt;strong&gt;SonarQube&lt;/strong&gt; automatically scans your code for bugs, security vulnerabilities, and code smells, giving developers actionable feedback on code quality and security.&lt;/p&gt;
&lt;p&gt;It integrates seamlessly with major CI/CD platforms: GitHub Actions, GitLab CI/CD, Azure Pipelines, and Jenkins. The killer feature is the Quality Gate, which lets you define specific quality and security thresholds. If your code doesn&amp;#39;t meet these standards, the pipeline fails. No bad code gets through.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SonarQube&lt;/strong&gt; also provides pull request decoration, showing developers feedback directly in their PRs. It integrates with IDEs for consistent analysis everywhere developers work. You get code coverage metrics and detailed reports on quality and security. &lt;strong&gt;SonarQube&lt;/strong&gt; helps enforce coding standards and regulatory compliance, ultimately boosting developer productivity through fast, helpful feedback.&lt;/p&gt;
&lt;p&gt;You can deploy it on your own servers, use the cloud version, or run it in Docker and Kubernetes. Higher editions support branch analysis and PR/MR scanning. For Jenkins users, there&amp;#39;s a dedicated SonarQube Scanner plugin. GitLab integration lets you import projects and see quality gate status right in merge requests. Azure DevOps has an extension for easy pipeline integration.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a simple Jenkins pipeline with SonarQube:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy&quot;&gt;// Security: Define pipeline with strict error handling
pipeline {
    agent any

    // Security: Set global timeout to prevent resource exhaustion
    options {
        timeout(time: 1, unit: &amp;#39;HOURS&amp;#39;)
        timestamps()
        disableConcurrentBuilds()
        buildDiscarder(logRotator(numToKeepStr: &amp;#39;10&amp;#39;))
    }

    // Security: Define required tools with specific versions
    tools {
        maven &amp;#39;Maven-3.9.6&amp;#39;
        jdk &amp;#39;JDK-17&amp;#39;
    }

    // Security: Define environment variables with validation
    environment {
        // Security: Mask sensitive values in logs
        SONAR_TOKEN = credentials(&amp;#39;sonarqube-token&amp;#39;)
        SONAR_HOST_URL = credentials(&amp;#39;sonarqube-url&amp;#39;)
        // Security: Set Maven options for secure builds
        MAVEN_OPTS = &amp;#39;-Xmx2048m -Dmaven.wagon.http.ssl.insecure=false -Dmaven.wagon.http.ssl.allowall=false&amp;#39;
    }

    stages {
        // Security: Validate environment before starting
        stage(&amp;#39;Validate Environment&amp;#39;) {
            steps {
                script {
                    // Security: Check required tools are available
                    sh &amp;#39;&amp;#39;&amp;#39;
                        set -euo pipefail

                        echo &amp;quot;Validating build environment...&amp;quot;

                        # Check Maven version
                        mvn --version || { echo &amp;quot;ERROR: Maven not found&amp;quot;; exit 1; }

                        # Check Java version
                        java -version || { echo &amp;quot;ERROR: Java not found&amp;quot;; exit 1; }

                        # Validate credentials are set
                        if [ -z &amp;quot;$SONAR_TOKEN&amp;quot; ]; then
                            echo &amp;quot;ERROR: SonarQube token not configured&amp;quot;
                            exit 1
                        fi

                        echo &amp;quot;✓ Environment validated successfully&amp;quot;
                    &amp;#39;&amp;#39;&amp;#39;
                }
            }
        }

        // Security: Checkout with validation
        stage(&amp;#39;Checkout&amp;#39;) {
            steps {
                script {
                    // Security: Clean workspace before checkout
                    deleteDir()

                    // Security: Checkout with specific branch validation
                    checkout([
                        $class: &amp;#39;GitSCM&amp;#39;,
                        branches: [[name: &amp;#39;*/main&amp;#39;]],
                        extensions: [
                            [$class: &amp;#39;CleanCheckout&amp;#39;],
                            [$class: &amp;#39;CloneOption&amp;#39;, depth: 0, noTags: false, reference: &amp;#39;&amp;#39;, shallow: false]
                        ],
                        userRemoteConfigs: [[
                            url: &amp;#39;https://github.com/yourorg/yourrepo.git&amp;#39;,
                            credentialsId: &amp;#39;github-credentials&amp;#39;
                        ]]
                    ])

                    // Security: Verify workspace integrity
                    sh &amp;#39;&amp;#39;&amp;#39;
                        set -euo pipefail

                        if [ ! -f &amp;quot;pom.xml&amp;quot; ]; then
                            echo &amp;quot;ERROR: pom.xml not found - invalid project structure&amp;quot;
                            exit 1
                        fi

                        echo &amp;quot;✓ Workspace validated&amp;quot;
                    &amp;#39;&amp;#39;&amp;#39;
                }
            }
        }

        // Security: Dependency vulnerability check
        stage(&amp;#39;Security: Dependency Check&amp;#39;) {
            steps {
                script {
                    sh &amp;#39;&amp;#39;&amp;#39;
                        set -euo pipefail

                        echo &amp;quot;Checking dependencies for known vulnerabilities...&amp;quot;

                        # Run OWASP Dependency Check
                        mvn org.owasp:dependency-check-maven:check \
                            -DfailBuildOnCVSS=7 \
                            -DskipTestScope=true \
                            -DsuppressionFile=dependency-check-suppressions.xml \
                            -Dformats=HTML,JSON,JUNIT || {
                                echo &amp;quot;WARNING: Vulnerabilities found in dependencies&amp;quot;
                                exit 0
                            }

                        echo &amp;quot;✓ Dependency check completed&amp;quot;
                    &amp;#39;&amp;#39;&amp;#39;
                }
            }
            post {
                always {
                    // Security: Archive dependency check report
                    publishHTML([
                        allowMissing: true,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: &amp;#39;target&amp;#39;,
                        reportFiles: &amp;#39;dependency-check-report.html&amp;#39;,
                        reportName: &amp;#39;OWASP Dependency Check&amp;#39;
                    ])
                }
            }
        }

        // Security: Secure build process
        stage(&amp;#39;Build&amp;#39;) {
            steps {
                script {
                    sh &amp;#39;&amp;#39;&amp;#39;
                        set -euo pipefail

                        echo &amp;quot;Building project with security checks...&amp;quot;

                        # Security: Build with strict compiler warnings
                        mvn clean package \
                            -DskipTests=false \
                            -Dmaven.test.failure.ignore=false \
                            -Dcheckstyle.failOnViolation=true \
                            -Denforcer.fail=true \
                            -B  # Batch mode for CI

                        # Security: Verify build artifacts
                        if [ ! -f &amp;quot;target/*.jar&amp;quot; ]; then
                            echo &amp;quot;ERROR: Build artifact not found&amp;quot;
                            exit 1
                        fi

                        echo &amp;quot;✓ Build completed successfully&amp;quot;
                    &amp;#39;&amp;#39;&amp;#39;
                }
            }
            post {
                success {
                    // Security: Archive build artifacts with checksum
                    script {
                        sh &amp;#39;sha256sum target/*.jar &amp;gt; target/checksums.txt&amp;#39;
                        archiveArtifacts artifacts: &amp;#39;target/*.jar,target/checksums.txt&amp;#39;, fingerprint: true
                    }
                }
            }
        }

        // Security: SonarQube SAST analysis
        stage(&amp;#39;SonarQube Analysis&amp;#39;) {
            steps {
                script {
                    def scannerHome = tool &amp;#39;SonarQubeScanner&amp;#39;

                    // Security: Run SonarQube with strict quality profiles
                    withSonarQubeEnv(&amp;#39;SonarQube&amp;#39;) {
                        sh &amp;quot;&amp;quot;&amp;quot;
                            set -euo pipefail

                            echo &amp;quot;Running SonarQube security analysis...&amp;quot;

                            # Security: Validate SonarQube URL
                            if ! echo &amp;quot;\$SONAR_HOST_URL&amp;quot; | grep -E &amp;#39;^https://[a-zA-Z0-9.-]+&amp;#39;; then
                                echo &amp;quot;ERROR: Invalid SonarQube URL&amp;quot;
                                exit 1
                            fi

                            # Run analysis with security-focused settings
                            ${scannerHome}/bin/sonar-scanner \
                                -Dsonar.projectKey=my-project \
                                -Dsonar.sources=src/main \
                                -Dsonar.tests=src/test \
                                -Dsonar.java.binaries=target/classes \
                                -Dsonar.java.test.binaries=target/test-classes \
                                -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml \
                                -Dsonar.exclusions=&amp;#39;**/test/**,**/node_modules/**&amp;#39; \
                                -Dsonar.log.level=INFO

                            echo &amp;quot;✓ SonarQube analysis completed&amp;quot;
                        &amp;quot;&amp;quot;&amp;quot;
                    }
                }
            }
        }

        // Security: Enforce quality gate
        stage(&amp;#39;Quality Gate&amp;#39;) {
            steps {
                script {
                    // Security: Wait for quality gate with timeout
                    timeout(time: 10, unit: &amp;#39;MINUTES&amp;#39;) {
                        def qg = waitForQualityGate()

                        if (qg.status != &amp;#39;OK&amp;#39;) {
                            // Security: Log quality gate failure
                            echo &amp;quot;ERROR: Quality Gate failed with status: ${qg.status}&amp;quot;
                            echo &amp;quot;Review security findings at: ${env.SONAR_HOST_URL}&amp;quot;

                            // Security: Fail the build
                            error &amp;quot;Quality Gate failed - security standards not met&amp;quot;
                        }

                        echo &amp;quot;✓ Quality Gate passed&amp;quot;
                    }
                }
            }
        }

        // Security: Conditional deployment
        stage(&amp;#39;Deploy&amp;#39;) {
            when {
                allOf {
                    branch &amp;#39;main&amp;#39;
                    expression { currentBuild.result == null || currentBuild.result == &amp;#39;SUCCESS&amp;#39; }
                }
            }
            steps {
                script {
                    sh &amp;#39;&amp;#39;&amp;#39;
                        set -euo pipefail

                        echo &amp;quot;Deploying application with security verification...&amp;quot;

                        # Security: Verify artifact integrity before deployment
                        if ! sha256sum -c target/checksums.txt; then
                            echo &amp;quot;ERROR: Artifact integrity check failed&amp;quot;
                            exit 1
                        fi

                        # Your secure deployment steps here
                        echo &amp;quot;✓ Deployment completed successfully&amp;quot;
                    &amp;#39;&amp;#39;&amp;#39;
                }
            }
        }
    }

    // Security: Post-build actions with notifications
    post {
        always {
            // Security: Clean workspace after build
            cleanWs()
        }

        success {
            echo &amp;#39;Pipeline completed successfully with all security checks passed&amp;#39;
        }

        failure {
            script {
                // Security: Send notification on failure
                emailext(
                    subject: &amp;quot;SECURITY ALERT: Pipeline Failed - ${currentBuild.fullDisplayName}&amp;quot;,
                    body: &amp;quot;&amp;quot;&amp;quot;
                        Build failed with security issues:

                        Project: ${env.JOB_NAME}
                        Build Number: ${env.BUILD_NUMBER}
                        Build URL: ${env.BUILD_URL}

                        Action Required: Review security findings before proceeding.
                    &amp;quot;&amp;quot;&amp;quot;,
                    to: &amp;#39;security-team@example.com&amp;#39;,
                    mimeType: &amp;#39;text/plain&amp;#39;
                )
            }
        }

        unstable {
            echo &amp;#39;Build unstable - review security warnings&amp;#39;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This pipeline builds your code, runs SonarQube analysis, waits for the quality gate result, and only deploys if everything passes. If the quality gate fails, the pipeline stops and notifies your team.&lt;/p&gt;
&lt;h3&gt;Using OWASP ZAP for Dynamic Security Testing in Your Pipeline&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;OWASP ZAP&lt;/strong&gt; (Zed Attack Proxy) is one of the most popular open-source tools for web application security testing, maintained by the Open Web Application Security Project. It works as a man-in-the-middle proxy, intercepting traffic between your browser and application to find security vulnerabilities.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OWASP ZAP&lt;/strong&gt; automatically detects common vulnerabilities like SQL injection and XSS. You can integrate it into CI/CD pipelines using official Docker images for automated security testing. The CLI makes automation easy, and the powerful API lets you script custom security tests.&lt;/p&gt;
&lt;p&gt;It offers different scan modes: quick passive scans and thorough active scans. Reports come in multiple formats (HTML, XML, JSON, Markdown) for easy sharing. Jenkins users get a dedicated plugin. You can also use it with GitLab CI via Docker and custom scripts, and with Azure DevOps through marketplace extensions.&lt;/p&gt;
&lt;p&gt;For faster CI/CD feedback, use the baseline scan for quick passive checks. It supports authenticated scans so you can test protected areas of your app. It&amp;#39;s also excellent for API security testing.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example Docker Compose setup for local DAST testing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;services:
  # Application under test
  app:
    image: myapp:latest
    container_name: dast-target-app

    # Security: Network isolation
    networks:
      - dast-network

    # Security: Resource limits to prevent DoS
    deploy:
      resources:
        limits:
          cpus: &amp;#39;1.0&amp;#39;
          memory: 1G
        reservations:
          cpus: &amp;#39;0.5&amp;#39;
          memory: 512M

    # Security: Port mapping (localhost only)
    ports:
      - &amp;#39;127.0.0.1:3000:3000&amp;#39;

    # Security: Environment variables (use .env file for secrets)
    environment:
      - NODE_ENV=test
      - LOG_LEVEL=info
      # Security: Disable debug modes in test
      - DEBUG=false

    # Security: Health check for readiness
    healthcheck:
      test:
        [
          &amp;#39;CMD&amp;#39;,
          &amp;#39;wget&amp;#39;,
          &amp;#39;--quiet&amp;#39;,
          &amp;#39;--tries=1&amp;#39;,
          &amp;#39;--spider&amp;#39;,
          &amp;#39;http://localhost:3000/health&amp;#39;,
        ]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

    # Security: Read-only root filesystem where possible
    read_only: true

    # Security: Drop unnecessary capabilities
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE

    # Security: Run as non-root user
    user: &amp;#39;1000:1000&amp;#39;

    # Security: Temporary volumes for writable paths
    tmpfs:
      - /tmp:noexec,nosuid,size=100M
      - /var/tmp:noexec,nosuid,size=100M

  # OWASP ZAP scanner
  zap:
    image: owasp/zap2docker-stable:latest
    container_name: dast-zap-scanner

    # Security: Network isolation
    networks:
      - dast-network

    # Security: Resource limits
    deploy:
      resources:
        limits:
          cpus: &amp;#39;2.0&amp;#39;
          memory: 2G
        reservations:
          cpus: &amp;#39;1.0&amp;#39;
          memory: 1G

    # Security: Wait for app to be healthy before scanning
    depends_on:
      app:
        condition: service_healthy

    # Security: Custom entrypoint for enhanced scanning
    entrypoint: [&amp;#39;/bin/bash&amp;#39;, &amp;#39;-c&amp;#39;]
    command:
      - |
        set -euo pipefail

        echo &amp;quot;Starting DAST security scan...&amp;quot;

        # Security: Wait for app to be fully ready
        sleep 10

        # Security: Create secure working directory
        mkdir -p /zap/wrk
        chmod 700 /zap/wrk

        # Security: Configure ZAP with safe settings
        cat &amp;gt; /zap/wrk/zap-options.prop &amp;lt;&amp;lt; &amp;#39;EOF&amp;#39;
        # Rate limiting to prevent DoS
        scanner.threadPerHost=2
        connection.timeoutInSecs=30
        # Disable risky attack vectors in test environment
        scanner.attackMode=standard
        EOF

        # Security: Run baseline scan with comprehensive reporting
        zap-baseline.py \
          -t http://app:3000 \
          -c /zap/wrk/zap-options.prop \
          -r /zap/wrk/dast-report.html \
          -w /zap/wrk/dast-report.md \
          -J /zap/wrk/dast-report.json \
          -x /zap/wrk/dast-report.xml \
          -d \
          -T 15 \
          -z &amp;quot;-config api.disablekey=true&amp;quot; || true

        # Security: Generate summary
        if [ -f &amp;quot;/zap/wrk/dast-report.json&amp;quot; ]; then
          echo &amp;quot;Scan completed. Analyzing results...&amp;quot;

          # Parse JSON for vulnerabilities
          HIGH_COUNT=$$(jq &amp;#39;[.site[].alerts[] | select(.riskdesc | startswith(&amp;quot;High&amp;quot;))] | length&amp;#39; /zap/wrk/dast-report.json 2&amp;gt;/dev/null || echo &amp;quot;0&amp;quot;)
          MEDIUM_COUNT=$$(jq &amp;#39;[.site[].alerts[] | select(.riskdesc | startswith(&amp;quot;Medium&amp;quot;))] | length&amp;#39; /zap/wrk/dast-report.json 2&amp;gt;/dev/null || echo &amp;quot;0&amp;quot;)
          LOW_COUNT=$$(jq &amp;#39;[.site[].alerts[] | select(.riskdesc | startswith(&amp;quot;Low&amp;quot;))] | length&amp;#39; /zap/wrk/dast-report.json 2&amp;gt;/dev/null || echo &amp;quot;0&amp;quot;)

          echo &amp;quot;========================================&amp;quot;
          echo &amp;quot;DAST Scan Results:&amp;quot;
          echo &amp;quot;  High Severity:   $$HIGH_COUNT&amp;quot;
          echo &amp;quot;  Medium Severity: $$MEDIUM_COUNT&amp;quot;
          echo &amp;quot;  Low Severity:    $$LOW_COUNT&amp;quot;
          echo &amp;quot;========================================&amp;quot;

          # Security: Set exit code based on findings
          if [ &amp;quot;$$HIGH_COUNT&amp;quot; -gt 0 ]; then
            echo &amp;quot;CRITICAL: High severity vulnerabilities detected!&amp;quot;
            exit 1
          fi
        else
          echo &amp;quot;ERROR: Scan report not generated&amp;quot;
          exit 1
        fi

        echo &amp;quot;DAST scan completed successfully&amp;quot;

    # Security: Mount reports directory with restricted permissions
    volumes:
      - type: bind
        source: ./reports
        target: /zap/wrk
        read_only: false

    # Security: Run as non-root user
    user: &amp;#39;1000:1000&amp;#39;

    # Security: Drop unnecessary capabilities
    cap_drop:
      - ALL

# Security: Isolated network for testing
networks:
  dast-network:
    driver: bridge
    internal: false
    ipam:
      config:
        - subnet: 172.28.0.0/16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&amp;#39;s a more advanced Azure DevOps pipeline with authenticated scanning:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Security: Azure DevOps DAST Pipeline with Comprehensive Controls
trigger:
  branches:
    include:
      - main
      - develop
  paths:
    exclude:
      - docs/*
      - &amp;#39;*.md&amp;#39;

# Security: Scheduled security scans
schedules:
  - cron: &amp;#39;0 2 * * 0&amp;#39; # Weekly scan on Sunday at 2 AM
    displayName: &amp;#39;Weekly Security Scan&amp;#39;
    branches:
      include:
        - main
    always: true

# Security: Define variables with validation
variables:
  - name: stagingUrl
    value: &amp;#39;https://staging.example.com&amp;#39;
  - name: zapTimeout
    value: &amp;#39;15&amp;#39;
  - name: maxScanDuration
    value: &amp;#39;30&amp;#39;
  # Security: Use variable groups for secrets
  - group: &amp;#39;security-credentials&amp;#39;

pool:
  vmImage: &amp;#39;ubuntu-22.04&amp;#39; # Use specific version

stages:
  - stage: Validate
    displayName: &amp;#39;Validate Configuration&amp;#39;
    jobs:
      - job: ValidateEnvironment
        displayName: &amp;#39;Validate Security Environment&amp;#39;
        timeoutInMinutes: 10
        steps:
          - bash: |
              set -euo pipefail

              echo &amp;quot;Validating security scan configuration...&amp;quot;

              # Security: Validate staging URL format
              if ! echo &amp;quot;$(stagingUrl)&amp;quot; | grep -E &amp;#39;^https://[a-zA-Z0-9.-]+&amp;#39;; then
                echo &amp;quot;##vso[task.logissue type=error]Invalid staging URL format - must use HTTPS&amp;quot;
                exit 1
              fi

              # Security: Check for required secrets
              if [ -z &amp;quot;$(stagingUsername)&amp;quot; ] || [ -z &amp;quot;$(stagingPassword)&amp;quot; ]; then
                echo &amp;quot;##vso[task.logissue type=error]Authentication credentials not configured&amp;quot;
                exit 1
              fi

              echo &amp;quot;✓ Configuration validated successfully&amp;quot;
            displayName: &amp;#39;Validate Configuration&amp;#39;

  - stage: SecurityTest
    displayName: &amp;#39;DAST Security Testing&amp;#39;
    dependsOn: Validate
    condition: succeeded()
    jobs:
      - job: PrepareScan
        displayName: &amp;#39;Prepare Security Scan&amp;#39;
        timeoutInMinutes: 10
        steps:
          # Security: Create secure working directory
          - bash: |
              set -euo pipefail

              mkdir -p $(Build.ArtifactStagingDirectory)/zap-config
              mkdir -p $(Build.ArtifactStagingDirectory)/zap-reports
              chmod 700 $(Build.ArtifactStagingDirectory)/zap-config

              echo &amp;quot;✓ Scan directories prepared&amp;quot;
            displayName: &amp;#39;Prepare Scan Environment&amp;#39;

      - job: DASTScan
        displayName: &amp;#39;Run DAST Security Scan&amp;#39;
        dependsOn: PrepareScan
        timeoutInMinutes: $(maxScanDuration)

        steps:
          # Security: Pull specific Docker image version
          - task: Docker@2
            displayName: &amp;#39;Pull OWASP ZAP Image&amp;#39;
            inputs:
              command: &amp;#39;pull&amp;#39;
              arguments: &amp;#39;owasp/zap2docker-stable:2.14.0&amp;#39;
            retryCountOnTaskFailure: 3

          # Security: Verify target availability before scanning
          - bash: |
              set -euo pipefail

              echo &amp;quot;Verifying target application is accessible...&amp;quot;

              MAX_RETRIES=10
              RETRY_COUNT=0

              while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
                if curl -sSf -m 10 &amp;quot;$(stagingUrl)/health&amp;quot; &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then
                  echo &amp;quot;✓ Target application is healthy&amp;quot;
                  exit 0
                fi

                RETRY_COUNT=$((RETRY_COUNT + 1))
                echo &amp;quot;Attempt $RETRY_COUNT/$MAX_RETRIES failed, retrying...&amp;quot;
                sleep 10
              done

              echo &amp;quot;##vso[task.logissue type=error]Target application not accessible&amp;quot;
              exit 1
            displayName: &amp;#39;Verify Target Availability&amp;#39;

          # Security: Create authenticated scan configuration
          - bash: |
              set -euo pipefail

              echo &amp;quot;Creating secure ZAP configuration...&amp;quot;

              # Security: Create authentication context with validation
              cat &amp;gt; $(Build.ArtifactStagingDirectory)/zap-config/auth-config.yaml &amp;lt;&amp;lt; EOF
              ---
              env:
                contexts:
                  - name: &amp;quot;Staging Environment&amp;quot;
                    urls:
                      - &amp;quot;$(stagingUrl)&amp;quot;
                    authentication:
                      method: &amp;quot;form&amp;quot;
                      parameters:
                        loginUrl: &amp;quot;$(stagingUrl)/login&amp;quot;
                        loginRequestData: &amp;quot;username={%username%}&amp;amp;password={%password%}&amp;quot;
                      verification:
                        method: &amp;quot;response&amp;quot;
                        loggedInRegex: &amp;quot;\\QLogout\\E&amp;quot;
                        loggedOutRegex: &amp;quot;\\QLogin\\E&amp;quot;
                    sessionManagement:
                      method: &amp;quot;cookie&amp;quot;
                users:
                  - name: &amp;quot;test-user&amp;quot;
                    credentials:
                      username: &amp;quot;\$(TEST_USERNAME)&amp;quot;
                      password: &amp;quot;\$(TEST_PASSWORD)&amp;quot;
              EOF

              # Security: Validate configuration file
              if [ ! -s &amp;quot;$(Build.ArtifactStagingDirectory)/zap-config/auth-config.yaml&amp;quot; ]; then
                echo &amp;quot;##vso[task.logissue type=error]Failed to create auth configuration&amp;quot;
                exit 1
              fi

              echo &amp;quot;✓ Authentication configuration created&amp;quot;
            displayName: &amp;#39;Create Auth Configuration&amp;#39;
            env:
              TEST_USERNAME: $(stagingUsername)
              TEST_PASSWORD: $(stagingPassword)

          # Security: Run comprehensive DAST scan
          - bash: |
              set -euo pipefail

              echo &amp;quot;Starting DAST security scan...&amp;quot;
              echo &amp;quot;Target: $(stagingUrl)&amp;quot;
              echo &amp;quot;Timeout: $(zapTimeout) minutes&amp;quot;

              # Security: Run ZAP with resource limits and timeout
              docker run --rm \
                --name zap-scanner-$(Build.BuildId) \
                --memory=2g \
                --cpus=2 \
                -v $(Build.ArtifactStagingDirectory)/zap-config:/zap/wrk/config:ro \
                -v $(Build.ArtifactStagingDirectory)/zap-reports:/zap/wrk/reports:rw \
                -e &amp;quot;ZAP_JAVA_OPTS=-Xmx1536m&amp;quot; \
                owasp/zap2docker-stable:2.14.0 \
                zap-full-scan.py \
                  -t &amp;quot;$(stagingUrl)&amp;quot; \
                  -n /zap/wrk/config/auth-config.yaml \
                  -U test-user \
                  -r /zap/wrk/reports/dast-report.html \
                  -w /zap/wrk/reports/dast-report.md \
                  -J /zap/wrk/reports/dast-report.json \
                  -x /zap/wrk/reports/dast-report.xml \
                  -d \
                  -T $(zapTimeout) \
                  -z &amp;quot;-config api.disablekey=true -config spider.maxDuration=$(zapTimeout) -config scanner.threadPerHost=2&amp;quot; \
                  || SCAN_EXIT_CODE=$?

              # Security: Analyze scan results
              if [ -f &amp;quot;$(Build.ArtifactStagingDirectory)/zap-reports/dast-report.json&amp;quot; ]; then
                echo &amp;quot;Analyzing scan results...&amp;quot;

                # Parse vulnerability counts
                HIGH_COUNT=$(jq &amp;#39;[.site[].alerts[] | select(.riskdesc | startswith(&amp;quot;High&amp;quot;))] | length&amp;#39; \
                  $(Build.ArtifactStagingDirectory)/zap-reports/dast-report.json 2&amp;gt;/dev/null || echo &amp;quot;0&amp;quot;)
                MEDIUM_COUNT=$(jq &amp;#39;[.site[].alerts[] | select(.riskdesc | startswith(&amp;quot;Medium&amp;quot;))] | length&amp;#39; \
                  $(Build.ArtifactStagingDirectory)/zap-reports/dast-report.json 2&amp;gt;/dev/null || echo &amp;quot;0&amp;quot;)
                LOW_COUNT=$(jq &amp;#39;[.site[].alerts[] | select(.riskdesc | startswith(&amp;quot;Low&amp;quot;))] | length&amp;#39; \
                  $(Build.ArtifactStagingDirectory)/zap-reports/dast-report.json 2&amp;gt;/dev/null || echo &amp;quot;0&amp;quot;)

                echo &amp;quot;========================================&amp;quot;
                echo &amp;quot;DAST Scan Results Summary:&amp;quot;
                echo &amp;quot;  High Severity:   $HIGH_COUNT&amp;quot;
                echo &amp;quot;  Medium Severity: $MEDIUM_COUNT&amp;quot;
                echo &amp;quot;  Low Severity:    $LOW_COUNT&amp;quot;
                echo &amp;quot;========================================&amp;quot;

                # Security: Set pipeline variables for reporting
                echo &amp;quot;##vso[task.setvariable variable=highVulnCount;isOutput=true]$HIGH_COUNT&amp;quot;
                echo &amp;quot;##vso[task.setvariable variable=mediumVulnCount;isOutput=true]$MEDIUM_COUNT&amp;quot;

                # Security: Fail on high severity findings
                if [ &amp;quot;$HIGH_COUNT&amp;quot; -gt 0 ]; then
                  echo &amp;quot;##vso[task.logissue type=error]Critical vulnerabilities detected: $HIGH_COUNT high severity issues&amp;quot;
                  exit 1
                fi

                echo &amp;quot;✓ DAST scan completed successfully&amp;quot;
              else
                echo &amp;quot;##vso[task.logissue type=error]Scan report not generated&amp;quot;
                exit 1
              fi
            displayName: &amp;#39;Run OWASP ZAP Scan&amp;#39;
            timeoutInMinutes: $(maxScanDuration)

          # Security: Sanitize reports before publishing
          - bash: |
              set -euo pipefail

              echo &amp;quot;Sanitizing scan reports...&amp;quot;

              # Security: Remove potential credentials from reports
              find $(Build.ArtifactStagingDirectory)/zap-reports -type f -exec \
                sed -i &amp;#39;s/$(stagingUsername)/***REDACTED***/g&amp;#39; {} \;

              # Security: Generate report summary
              cat &amp;gt; $(Build.ArtifactStagingDirectory)/zap-reports/scan-summary.txt &amp;lt;&amp;lt; EOF
              DAST Security Scan Summary
              ==========================
              Build ID: $(Build.BuildId)
              Target URL: $(stagingUrl)
              Scan Date: $(date -u +&amp;quot;%Y-%m-%d %H:%M:%S UTC&amp;quot;)
              Pipeline: $(Build.DefinitionName)

              Reports generated:
              - HTML: dast-report.html
              - JSON: dast-report.json
              - XML: dast-report.xml
              - Markdown: dast-report.md
              EOF

              echo &amp;quot;✓ Reports sanitized&amp;quot;
            displayName: &amp;#39;Sanitize Reports&amp;#39;
            condition: always()

          # Security: Publish scan artifacts
          - task: PublishBuildArtifacts@1
            displayName: &amp;#39;Publish DAST Reports&amp;#39;
            inputs:
              PathtoPublish: &amp;#39;$(Build.ArtifactStagingDirectory)/zap-reports&amp;#39;
              ArtifactName: &amp;#39;dast-security-reports-$(Build.BuildId)&amp;#39;
              publishLocation: &amp;#39;Container&amp;#39;
            condition: always()

          # Security: Publish test results
          - task: PublishTestResults@2
            displayName: &amp;#39;Publish Test Results&amp;#39;
            inputs:
              testResultsFormat: &amp;#39;JUnit&amp;#39;
              testResultsFiles: &amp;#39;$(Build.ArtifactStagingDirectory)/zap-reports/dast-report.xml&amp;#39;
              testRunTitle: &amp;#39;DAST Security Scan&amp;#39;
              mergeTestResults: true
              failTaskOnFailedTests: true
            condition: always()

  - stage: Report
    displayName: &amp;#39;Security Reporting&amp;#39;
    dependsOn: SecurityTest
    condition: always()
    jobs:
      - job: GenerateReport
        displayName: &amp;#39;Generate Security Report&amp;#39;
        steps:
          # Security: Send notification on findings
          - bash: |
              set -euo pipefail

              echo &amp;quot;Generating security report summary...&amp;quot;

              # Add custom reporting logic here
              echo &amp;quot;✓ Security scan completed&amp;quot;
              echo &amp;quot;Review detailed findings in published artifacts&amp;quot;
            displayName: &amp;#39;Generate Summary&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup tests authenticated areas of your app, which is where most interesting vulnerabilities hide. The scan results are published as artifacts you can review after the pipeline runs.&lt;/p&gt;
&lt;h3&gt;Leveraging Trivy for Vulnerability Scanning in CI/CD&lt;/h3&gt;
&lt;p&gt;Trivy is a fast, comprehensive open-source vulnerability scanner from Aqua Security. It&amp;#39;s designed to be simple and fast, making it perfect for CI/CD pipelines. Trivy scans containers, filesystems, and Git repositories for security issues. The best part? It&amp;#39;s incredibly easy to install and use, usually requiring zero configuration (no database setup needed).&lt;/p&gt;
&lt;p&gt;Trivy&amp;#39;s speed makes it ideal for fast-paced CI/CD workflows. Its design fits the DevSecOps philosophy, letting security teams easily add vulnerability scanning to existing CI pipelines. You can use it as a CLI tool or Docker container, giving you flexibility.&lt;/p&gt;
&lt;p&gt;It checks for OS package vulnerabilities, application dependency vulnerabilities, and other known security issues. Beyond vulnerabilities, Trivy scans Dockerfiles and Kubernetes manifests for misconfigurations. It outputs results in multiple formats (JSON, HTML) for easy integration with reporting tools.&lt;/p&gt;
&lt;p&gt;Crucially for CI/CD, Trivy can fail your build if it finds critical issues, preventing insecure code or containers from being deployed. It has specific integrations for GitHub Actions, Azure DevOps, CircleCI, GitLab CI, and Jenkins. Trivy generates SBOMs for detailed component visibility. There&amp;#39;s a Jenkins plugin available, and GitLab has built-in container scanning templates using Trivy.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a comprehensive example for a Node.js application in GitLab CI:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Security: Comprehensive GitLab CI Pipeline with Trivy
stages:
  - validate
  - build
  - scan
  - report
  - deploy

# Security: Global variables with safe defaults
variables:
  # Docker image settings
  IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  LATEST_IMAGE: $CI_REGISTRY_IMAGE:latest
  # Security: Enable BuildKit for better security
  DOCKER_BUILDKIT: &amp;#39;1&amp;#39;
  # Security: Set scan timeouts
  TRIVY_TIMEOUT: &amp;#39;15m&amp;#39;
  # Security: Fail on high/critical vulnerabilities
  FAIL_ON_SEVERITY: &amp;#39;CRITICAL,HIGH&amp;#39;

# Security: Reusable configuration
.security_template:
  retry:
    max: 2
    when:
      - runner_system_failure
      - stuck_or_timeout_failure

# Security: Validate pipeline configuration
validate_config:
  stage: validate
  image: alpine:3.19
  script:
    - |
      set -euo pipefail

      echo &amp;quot;Validating pipeline configuration...&amp;quot;

      # Security: Check required variables
      if [ -z &amp;quot;${CI_REGISTRY_IMAGE:-}&amp;quot; ]; then
        echo &amp;quot;ERROR: CI_REGISTRY_IMAGE not set&amp;quot;
        exit 1
      fi

      if [ -z &amp;quot;${CI_COMMIT_SHORT_SHA:-}&amp;quot; ]; then
        echo &amp;quot;ERROR: CI_COMMIT_SHORT_SHA not set&amp;quot;
        exit 1
      fi

      echo &amp;quot;✓ Configuration validated&amp;quot;
  only:
    - branches
    - tags

# Security: Build Docker image with controls
build:
  stage: build
  image: docker:24-cli
  services:
    - docker:24-dind

  # Security: Set resource limits
  timeout: 30 minutes

  variables:
    # Security: DinD configuration
    DOCKER_TLS_CERTDIR: &amp;#39;/certs&amp;#39;
    DOCKER_DRIVER: overlay2

  before_script:
    - |
      set -euo pipefail

      # Security: Validate Docker daemon
      if ! docker info &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
        echo &amp;quot;ERROR: Docker daemon not available&amp;quot;
        exit 1
      fi

      # Security: Login to registry
      echo &amp;quot;$CI_REGISTRY_PASSWORD&amp;quot; | docker login -u &amp;quot;$CI_REGISTRY_USER&amp;quot; --password-stdin &amp;quot;$CI_REGISTRY&amp;quot;

  script:
    - |
      set -euo pipefail

      echo &amp;quot;Building Docker image: $IMAGE_NAME&amp;quot;

      # Security: Validate Dockerfile
      if [ ! -f &amp;quot;Dockerfile&amp;quot; ]; then
        echo &amp;quot;ERROR: Dockerfile not found&amp;quot;
        exit 1
      fi

      # Security: Scan Dockerfile for issues
      docker run --rm -i hadolint/hadolint:latest &amp;lt; Dockerfile || true

      # Security: Build with security best practices
      docker build \
        --no-cache \
        --pull \
        --label &amp;quot;org.opencontainers.image.created=$(date -u +&amp;#39;%Y-%m-%dT%H:%M:%SZ&amp;#39;)&amp;quot; \
        --label &amp;quot;org.opencontainers.image.revision=$CI_COMMIT_SHA&amp;quot; \
        --label &amp;quot;org.opencontainers.image.source=$CI_PROJECT_URL&amp;quot; \
        --label &amp;quot;org.opencontainers.image.version=$CI_COMMIT_SHORT_SHA&amp;quot; \
        --tag &amp;quot;$IMAGE_NAME&amp;quot; \
        --tag &amp;quot;$LATEST_IMAGE&amp;quot; \
        .

      # Security: Push image
      docker push &amp;quot;$IMAGE_NAME&amp;quot;
      docker push &amp;quot;$LATEST_IMAGE&amp;quot;

      echo &amp;quot;✓ Image built and pushed successfully&amp;quot;

  only:
    - branches
    - tags

# Security: Scan filesystem for vulnerabilities
trivy_fs_scan:
  stage: scan
  image:
    name: aquasec/trivy:0.48.3
    entrypoint: [&amp;#39;&amp;#39;]

  timeout: 20 minutes

  extends: .security_template

  script:
    - |
      set -euo pipefail

      echo &amp;quot;Scanning filesystem for vulnerabilities...&amp;quot;

      # Security: Comprehensive filesystem scan
      trivy fs \
        --exit-code 0 \
        --severity &amp;quot;${FAIL_ON_SEVERITY},MEDIUM&amp;quot; \
        --format json \
        --output trivy-fs-report.json \
        --scanners vuln,secret,config \
        --timeout &amp;quot;${TRIVY_TIMEOUT}&amp;quot; \
        .

      # Security: Generate human-readable report
      trivy fs \
        --severity &amp;quot;${FAIL_ON_SEVERITY},MEDIUM,LOW&amp;quot; \
        --format table \
        --output trivy-fs-report.txt \
        .

      # Security: Parse results
      if [ -f &amp;quot;trivy-fs-report.json&amp;quot; ]; then
        CRITICAL_COUNT=$(jq &amp;#39;[.Results[].Vulnerabilities[]? | select(.Severity==&amp;quot;CRITICAL&amp;quot;)] | length&amp;#39; trivy-fs-report.json)
        HIGH_COUNT=$(jq &amp;#39;[.Results[].Vulnerabilities[]? | select(.Severity==&amp;quot;HIGH&amp;quot;)] | length&amp;#39; trivy-fs-report.json)

        echo &amp;quot;Filesystem Scan Results:&amp;quot;
        echo &amp;quot;  Critical: $CRITICAL_COUNT&amp;quot;
        echo &amp;quot;  High: $HIGH_COUNT&amp;quot;
      fi

      # Security: Fail on critical vulnerabilities
      trivy fs \
        --exit-code 1 \
        --severity CRITICAL \
        --format table \
        . || {
          echo &amp;quot;ERROR: Critical vulnerabilities detected in filesystem&amp;quot;
          exit 1
        }

      echo &amp;quot;✓ Filesystem scan completed&amp;quot;

  artifacts:
    name: &amp;#39;trivy-fs-scan-$CI_COMMIT_SHORT_SHA&amp;#39;
    reports:
      dependency_scanning: trivy-fs-report.json
    paths:
      - trivy-fs-report.json
      - trivy-fs-report.txt
    expire_in: 90 days
    when: always

  allow_failure: false

  only:
    - branches
    - tags

# Security: Scan Docker image for vulnerabilities
trivy_image_scan:
  stage: scan
  image:
    name: aquasec/trivy:0.48.3
    entrypoint: [&amp;#39;&amp;#39;]
  services:
    - docker:24-dind

  timeout: 25 minutes

  extends: .security_template

  dependencies:
    - build

  variables:
    DOCKER_TLS_CERTDIR: &amp;#39;/certs&amp;#39;

  before_script:
    - |
      set -euo pipefail

      # Security: Verify Docker connectivity
      if ! docker info &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
        echo &amp;quot;ERROR: Cannot connect to Docker daemon&amp;quot;
        exit 1
      fi

      # Security: Login to registry
      echo &amp;quot;$CI_REGISTRY_PASSWORD&amp;quot; | docker login -u &amp;quot;$CI_REGISTRY_USER&amp;quot; --password-stdin &amp;quot;$CI_REGISTRY&amp;quot;

  script:
    - |
      set -euo pipefail

      echo &amp;quot;Scanning Docker image: $IMAGE_NAME&amp;quot;

      # Security: Comprehensive image scan
      trivy image \
        --exit-code 0 \
        --severity &amp;quot;${FAIL_ON_SEVERITY},MEDIUM&amp;quot; \
        --format json \
        --output trivy-image-report.json \
        --scanners vuln,secret,config \
        --timeout &amp;quot;${TRIVY_TIMEOUT}&amp;quot; \
        &amp;quot;$IMAGE_NAME&amp;quot;

      # Security: Generate table report
      trivy image \
        --severity &amp;quot;${FAIL_ON_SEVERITY},MEDIUM&amp;quot; \
        --format table \
        --output trivy-image-report.txt \
        &amp;quot;$IMAGE_NAME&amp;quot;

      # Security: Generate SBOM
      echo &amp;quot;Generating SBOM...&amp;quot;
      trivy image \
        --format cyclonedx \
        --output sbom.json \
        &amp;quot;$IMAGE_NAME&amp;quot;

      # Security: Validate SBOM
      if ! jq empty sbom.json 2&amp;gt;/dev/null; then
        echo &amp;quot;WARNING: Invalid SBOM format&amp;quot;
      fi

      # Security: Parse and report findings
      if [ -f &amp;quot;trivy-image-report.json&amp;quot; ]; then
        CRITICAL_COUNT=$(jq &amp;#39;[.Results[].Vulnerabilities[]? | select(.Severity==&amp;quot;CRITICAL&amp;quot;)] | length&amp;#39; trivy-image-report.json)
        HIGH_COUNT=$(jq &amp;#39;[.Results[].Vulnerabilities[]? | select(.Severity==&amp;quot;HIGH&amp;quot;)] | length&amp;#39; trivy-image-report.json)
        MEDIUM_COUNT=$(jq &amp;#39;[.Results[].Vulnerabilities[]? | select(.Severity==&amp;quot;MEDIUM&amp;quot;)] | length&amp;#39; trivy-image-report.json)

        echo &amp;quot;========================================&amp;quot;
        echo &amp;quot;Image Scan Results:&amp;quot;
        echo &amp;quot;  Critical: $CRITICAL_COUNT&amp;quot;
        echo &amp;quot;  High: $HIGH_COUNT&amp;quot;
        echo &amp;quot;  Medium: $MEDIUM_COUNT&amp;quot;
        echo &amp;quot;========================================&amp;quot;
      fi

      # Security: Fail on critical/high vulnerabilities
      trivy image \
        --exit-code 1 \
        --severity &amp;quot;${FAIL_ON_SEVERITY}&amp;quot; \
        --format table \
        &amp;quot;$IMAGE_NAME&amp;quot; || {
          echo &amp;quot;ERROR: Critical/High vulnerabilities detected in image&amp;quot;
          exit 1
        }

      echo &amp;quot;✓ Image scan completed successfully&amp;quot;

  artifacts:
    name: &amp;#39;trivy-image-scan-$CI_COMMIT_SHORT_SHA&amp;#39;
    reports:
      container_scanning: trivy-image-report.json
    paths:
      - trivy-image-report.json
      - trivy-image-report.txt
      - sbom.json
    expire_in: 90 days
    when: always

  allow_failure: false

  only:
    - branches
    - tags

# Security: Scan Kubernetes manifests
trivy_config_scan:
  stage: scan
  image:
    name: aquasec/trivy:0.48.3
    entrypoint: [&amp;#39;&amp;#39;]

  timeout: 15 minutes

  extends: .security_template

  script:
    - |
      set -euo pipefail

      # Security: Check if k8s directory exists
      if [ ! -d &amp;quot;./k8s&amp;quot; ]; then
        echo &amp;quot;INFO: No Kubernetes manifests found, skipping config scan&amp;quot;
        exit 0
      fi

      echo &amp;quot;Scanning Kubernetes configurations...&amp;quot;

      # Security: Scan configurations
      trivy config \
        --exit-code 0 \
        --severity &amp;quot;${FAIL_ON_SEVERITY},MEDIUM&amp;quot; \
        --format json \
        --output trivy-config-report.json \
        --timeout &amp;quot;${TRIVY_TIMEOUT}&amp;quot; \
        ./k8s

      # Security: Generate table report
      trivy config \
        --severity &amp;quot;${FAIL_ON_SEVERITY},MEDIUM,LOW&amp;quot; \
        --format table \
        --output trivy-config-report.txt \
        ./k8s

      # Security: Fail on high severity misconfigurations
      trivy config \
        --exit-code 1 \
        --severity &amp;quot;${FAIL_ON_SEVERITY}&amp;quot; \
        --format table \
        ./k8s || {
          echo &amp;quot;WARNING: High severity misconfigurations detected&amp;quot;
          exit 0  # Don&amp;#39;t block on config issues
        }

      echo &amp;quot;✓ Configuration scan completed&amp;quot;

  artifacts:
    name: &amp;#39;trivy-config-scan-$CI_COMMIT_SHORT_SHA&amp;#39;
    paths:
      - trivy-config-report.json
      - trivy-config-report.txt
    expire_in: 90 days
    when: always

  allow_failure: true # Config warnings shouldn&amp;#39;t block deployment

  only:
    - branches
    - tags

# Security: Generate consolidated report
generate_report:
  stage: report
  image: alpine:3.19

  dependencies:
    - trivy_fs_scan
    - trivy_image_scan
    - trivy_config_scan

  before_script:
    - apk add --no-cache jq

  script:
    - |
      set -euo pipefail

      echo &amp;quot;Generating consolidated security report...&amp;quot;

      cat &amp;gt; security-report.md &amp;lt;&amp;lt; EOF
      # Security Scan Report

      **Project:** $CI_PROJECT_NAME
      **Commit:** $CI_COMMIT_SHORT_SHA
      **Pipeline:** $CI_PIPELINE_ID
      **Date:** $(date -u +&amp;quot;%Y-%m-%d %H:%M:%S UTC&amp;quot;)

      ## Scan Results Summary

      EOF

      # Add filesystem scan results
      if [ -f &amp;quot;trivy-fs-report.txt&amp;quot; ]; then
        echo &amp;quot;### Filesystem Scan&amp;quot; &amp;gt;&amp;gt; security-report.md
        echo &amp;#39;```&amp;#39; &amp;gt;&amp;gt; security-report.md
        head -n 50 trivy-fs-report.txt &amp;gt;&amp;gt; security-report.md
        echo &amp;#39;```&amp;#39; &amp;gt;&amp;gt; security-report.md
        echo &amp;quot;&amp;quot; &amp;gt;&amp;gt; security-report.md
      fi

      # Add image scan results
      if [ -f &amp;quot;trivy-image-report.txt&amp;quot; ]; then
        echo &amp;quot;### Container Image Scan&amp;quot; &amp;gt;&amp;gt; security-report.md
        echo &amp;#39;```&amp;#39; &amp;gt;&amp;gt; security-report.md
        head -n 50 trivy-image-report.txt &amp;gt;&amp;gt; security-report.md
        echo &amp;#39;```&amp;#39; &amp;gt;&amp;gt; security-report.md
        echo &amp;quot;&amp;quot; &amp;gt;&amp;gt; security-report.md
      fi

      echo &amp;quot;✓ Consolidated report generated&amp;quot;

  artifacts:
    name: &amp;#39;security-report-$CI_COMMIT_SHORT_SHA&amp;#39;
    paths:
      - security-report.md
    expire_in: 90 days

  only:
    - branches
    - tags

# Security: Deploy only if scans pass
deploy:
  stage: deploy
  image: alpine:3.19

  dependencies:
    - build
    - trivy_fs_scan
    - trivy_image_scan

  script:
    - |
      set -euo pipefail

      echo &amp;quot;Deploying $IMAGE_NAME...&amp;quot;

      # Security: Verify all scans passed
      echo &amp;quot;✓ All security scans passed&amp;quot;
      echo &amp;quot;✓ Deployment authorized&amp;quot;

      # Your deployment commands here

  only:
    - main
    - tags

  when: manual # Require manual approval for production
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This pipeline scans three things: your filesystem for vulnerable dependencies, your Docker image for OS and app vulnerabilities, and your Kubernetes configs for misconfigurations. It generates an SBOM and fails the build if critical or high-severity issues are found. You get comprehensive security coverage without slowing down your pipeline significantly.&lt;/p&gt;
&lt;h2&gt;Navigating the Shift: Challenges and Best Practices&lt;/h2&gt;
&lt;h3&gt;What are Some Common Challenges When Implementing Shift-Left Security?&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s be real: implementing shift-left security isn&amp;#39;t always smooth sailing. You&amp;#39;ll face resistance to change. Development, security, and ops teams might push back against new practices and tools. Getting everyone on board takes time and patience.&lt;/p&gt;
&lt;p&gt;Knowledge gaps are another big hurdle. If your teams lack security expertise, making shift-left work is tough. Often, security tools don&amp;#39;t play nicely with development tools, causing visibility issues and friction. Then there&amp;#39;s alert fatigue. Automated security tools can flood developers with alerts and false positives, leading them to ignore important warnings. You&amp;#39;re also trying to balance thorough security testing with the pressure to ship fast.&lt;/p&gt;
&lt;p&gt;Other headaches include incomplete testing, failing to maintain the pipeline, underestimating scalability needs, and struggling with configuration management across different environments. Debugging and reporting within CI/CD pipelines can be tricky. Version conflicts might pop up when introducing new security checks.&lt;/p&gt;
&lt;p&gt;You might not have fully automated security tools that fit well into CI/CD, or you lack consistent security practices across your infrastructure. There&amp;#39;s the constant worry that security testing will slow down development. Developer adoption can be the biggest challenge, especially if they see security as extra work or if they&amp;#39;re only measured on feature velocity, not code security.&lt;/p&gt;
&lt;p&gt;Sometimes security tools don&amp;#39;t match your organization&amp;#39;s specific needs. Scaling shift-left across large, complex organizations is a massive undertaking. Early in development, you can&amp;#39;t always predict runtime issues. And there&amp;#39;s a risk of overloading developers with security responsibilities, expecting them to become security experts on top of everything else they do.&lt;/p&gt;
&lt;h3&gt;What are the Best Practices for a Successful Shift-Left Implementation in CI/CD?&lt;/h3&gt;
&lt;p&gt;Making shift-left work requires clear security policies that everyone understands. No ambiguity. Automate security testing (&lt;strong&gt;SAST&lt;/strong&gt;, &lt;strong&gt;DAST&lt;/strong&gt;, and &lt;strong&gt;SCA&lt;/strong&gt;) throughout your CI/CD pipeline to catch issues early without slowing things down. Train developers on secure coding and security tool usage. This isn&amp;#39;t optional – it&amp;#39;s essential for making security a priority.&lt;/p&gt;
&lt;p&gt;Foster collaboration between dev, security, and ops teams (that&amp;#39;s the DevSecOps mindset). When everyone works together and shares responsibility, security goals become clearer. Prioritize findings so teams know what to fix first. Not all vulnerabilities are created equal.&lt;/p&gt;
&lt;p&gt;Keep your security tools and dependencies updated to stay ahead of new threats. Have clear remediation workflows so vulnerabilities get fixed quickly. Configure tools to reduce false positives so developers can focus on real issues. Make security everyone&amp;#39;s job and create a culture where everyone contributes to building secure software.&lt;/p&gt;
&lt;p&gt;Continuously monitor and improve your security practices based on feedback and emerging threats. Start by thinking about security requirements early and add security checks to code reviews. Use tools that automate security and enable collaboration. Track security metrics throughout development and maintain current security documentation.&lt;/p&gt;
&lt;p&gt;First, assess your current development process to find where you can effectively shift left. Create a new shift-left security strategy with clear goals and responsibilities. Implement gradually, starting with easy wins. Try to replicate your production environment early in the process.&lt;/p&gt;
&lt;p&gt;Encourage early and frequent testing. Use automation for continuous integration and delivery. Carefully evaluate and monitor third-party software. Build a strong security awareness culture among developers. Give them the right tools and knowledge. Always monitor and improve your security policies to keep up with new threats.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a practical example of a comprehensive security pipeline that combines all three approaches:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Security: Complete Shift-Left Security Pipeline with All Controls
name: Complete Security Pipeline

# Security: Controlled trigger conditions
on:
  push:
    branches: [main, develop]
    paths-ignore:
      - &amp;#39;**.md&amp;#39;
      - &amp;#39;docs/**&amp;#39;
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened]
  schedule:
    # Security: Weekly comprehensive scan
    - cron: &amp;#39;0 3 * * 0&amp;#39;
  workflow_dispatch: # Manual security audits

# Security: Minimal required permissions (OIDC best practice)
permissions:
  contents: read
  security-events: write
  pull-requests: write
  deployments: write
  statuses: write

# Security: Environment variables
env:
  # Security: Set global timeout
  GLOBAL_TIMEOUT: 120
  # Security: Enable fail-fast on critical issues
  FAIL_ON_CRITICAL: &amp;#39;true&amp;#39;

jobs:
  # Security: Pre-flight validation
  validate:
    name: Validate Pipeline Configuration
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Validate Environment
        run: |
          set -euo pipefail

          echo &amp;quot;Validating pipeline environment...&amp;quot;

          # Security: Verify required secrets
          REQUIRED_SECRETS=(&amp;quot;SONAR_TOKEN&amp;quot; &amp;quot;SONAR_HOST_URL&amp;quot; &amp;quot;STAGING_URL&amp;quot;)
          for secret in &amp;quot;${REQUIRED_SECRETS[@]}&amp;quot;; do
            if [ -z &amp;quot;${!secret:-}&amp;quot; ]; then
              echo &amp;quot;::error::Required secret $secret not configured&amp;quot;
              exit 1
            fi
          done

          echo &amp;quot;✓ Environment validated&amp;quot;

  # Security: Static Analysis (SAST) - Fast feedback
  sast:
    name: Static Analysis (SAST)
    runs-on: ubuntu-latest
    needs: validate
    timeout-minutes: 30

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          java-version: &amp;#39;17&amp;#39;
          distribution: &amp;#39;temurin&amp;#39;
          cache: &amp;#39;maven&amp;#39;

      # Security: Run SonarQube with strict settings
      - name: Run SonarQube Scan
        uses: sonarsource/sonarqube-scan-action@v2
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
        with:
          args: &amp;gt;
            -Dsonar.qualitygate.wait=true
            -Dsonar.qualitygate.timeout=300
            -Dsonar.exclusions=**/test/**,**/node_modules/**

      # Security: Enforce quality gate
      - name: Check Quality Gate
        uses: sonarsource/sonarqube-quality-gate-action@v1
        timeout-minutes: 5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

      - name: Upload SAST Results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: sast-results-${{ github.run_number }}
          path: .scannerwork/
          retention-days: 90

  # Security: Software Composition Analysis (SCA) - Parallel with SAST
  sca:
    name: Dependency Scan (SCA)
    runs-on: ubuntu-latest
    needs: validate
    timeout-minutes: 20

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          persist-credentials: false

      # Security: Comprehensive filesystem scan
      - name: Run Trivy Filesystem Scan
        uses: aquasecurity/trivy-action@0.16.1
        with:
          scan-type: &amp;#39;fs&amp;#39;
          scan-ref: &amp;#39;.&amp;#39;
          format: &amp;#39;sarif&amp;#39;
          output: &amp;#39;trivy-fs-results.sarif&amp;#39;
          severity: &amp;#39;CRITICAL,HIGH&amp;#39;
          scanners: &amp;#39;vuln,secret,config&amp;#39;
          timeout: &amp;#39;15m&amp;#39;

      - name: Upload to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: &amp;#39;trivy-fs-results.sarif&amp;#39;
          category: &amp;#39;sca-filesystem&amp;#39;

      # Security: Fail on critical vulnerabilities
      - name: Check Vulnerability Threshold
        uses: aquasecurity/trivy-action@0.16.1
        with:
          scan-type: &amp;#39;fs&amp;#39;
          scan-ref: &amp;#39;.&amp;#39;
          exit-code: &amp;#39;1&amp;#39;
          severity: &amp;#39;CRITICAL,HIGH&amp;#39;
          scanners: &amp;#39;vuln&amp;#39;
          ignore-unfixed: true

  # Security: Build and scan container
  build_and_scan:
    name: Build &amp;amp; Scan Container
    runs-on: ubuntu-latest
    needs: [sast, sca]
    timeout-minutes: 40

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          persist-credentials: false

      # Security: Set up Docker Buildx
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      # Security: Build with security labels
      - name: Build Docker Image
        run: |
          set -euo pipefail

          # Security: Validate Dockerfile
          if [ ! -f &amp;quot;Dockerfile&amp;quot; ]; then
            echo &amp;quot;::error::Dockerfile not found&amp;quot;
            exit 1
          fi

          # Security: Lint Dockerfile
          docker run --rm -i hadolint/hadolint &amp;lt; Dockerfile

          # Security: Build with metadata
          docker build \
            --no-cache \
            --pull \
            --label &amp;quot;org.opencontainers.image.created=$(date -u +&amp;#39;%Y-%m-%dT%H:%M:%SZ&amp;#39;)&amp;quot; \
            --label &amp;quot;org.opencontainers.image.revision=${{ github.sha }}&amp;quot; \
            --label &amp;quot;org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}&amp;quot; \
            -t myapp:${{ github.sha }} \
            .

      # Security: Scan container image
      - name: Scan Container Image
        uses: aquasecurity/trivy-action@0.16.1
        with:
          image-ref: &amp;#39;myapp:${{ github.sha }}&amp;#39;
          format: &amp;#39;sarif&amp;#39;
          output: &amp;#39;trivy-image-results.sarif&amp;#39;
          severity: &amp;#39;CRITICAL,HIGH,MEDIUM&amp;#39;
          scanners: &amp;#39;vuln,secret,config&amp;#39;

      - name: Upload Image Scan Results
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: &amp;#39;trivy-image-results.sarif&amp;#39;
          category: &amp;#39;container-image&amp;#39;

      # Security: Generate SBOM
      - name: Generate SBOM
        run: |
          set -euo pipefail

          docker run --rm \
            -v /var/run/docker.sock:/var/run/docker.sock \
            aquasec/trivy image \
            --format cyclonedx \
            --output sbom.json \
            myapp:${{ github.sha }}

          # Validate SBOM
          if ! jq empty sbom.json; then
            echo &amp;quot;::error::Invalid SBOM format&amp;quot;
            exit 1
          fi

      - name: Upload SBOM
        uses: actions/upload-artifact@v4
        with:
          name: sbom-${{ github.run_number }}
          path: sbom.json
          retention-days: 90

      # Security: Save image for deployment
      - name: Save Docker Image
        run: |
          docker save myapp:${{ github.sha }} | gzip &amp;gt; myapp.tar.gz

      - name: Upload Image Artifact
        uses: actions/upload-artifact@v4
        with:
          name: docker-image-${{ github.run_number }}
          path: myapp.tar.gz
          retention-days: 7

  # Security: Deploy to staging with health checks
  deploy_staging:
    name: Deploy to Staging
    runs-on: ubuntu-latest
    needs: build_and_scan
    timeout-minutes: 20
    environment:
      name: staging
      url: ${{ secrets.STAGING_URL }}

    steps:
      - name: Download Docker Image
        uses: actions/download-artifact@v4
        with:
          name: docker-image-${{ github.run_number }}

      - name: Load and Deploy Image
        run: |
          set -euo pipefail

          # Load image
          docker load &amp;lt; myapp.tar.gz

          echo &amp;quot;Deploying to staging...&amp;quot;
          # Your deployment commands here

          # Security: Wait for health check
          MAX_RETRIES=30
          RETRY_COUNT=0

          while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
            if curl -sSf &amp;quot;${{ secrets.STAGING_URL }}/health&amp;quot;; then
              echo &amp;quot;✓ Staging deployment healthy&amp;quot;
              exit 0
            fi
            RETRY_COUNT=$((RETRY_COUNT + 1))
            sleep 10
          done

          echo &amp;quot;::error::Staging deployment health check failed&amp;quot;
          exit 1

  # Security: Dynamic Analysis (DAST) against staging
  dast:
    name: Dynamic Analysis (DAST)
    runs-on: ubuntu-latest
    needs: deploy_staging
    timeout-minutes: 45

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      # Security: Run OWASP ZAP scan
      - name: OWASP ZAP Baseline Scan
        uses: zaproxy/action-baseline@v0.10.0
        with:
          target: ${{ secrets.STAGING_URL }}
          rules_file_name: &amp;#39;.zap/rules.tsv&amp;#39;
          cmd_options: &amp;#39;-a -j -T 20&amp;#39;
          fail_action: true

      - name: Upload DAST Report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: dast-report-${{ github.run_number }}
          path: |
            report_html.html
            report_json.json
          retention-days: 90

  # Security: Security gate before production
  security_gate:
    name: Security Gate Review
    runs-on: ubuntu-latest
    needs: [sast, sca, build_and_scan, dast]
    if: always()
    timeout-minutes: 10

    steps:
      - name: Check All Security Scans
        run: |
          set -euo pipefail

          echo &amp;quot;Reviewing all security scan results...&amp;quot;

          # Security: Verify all jobs passed
          NEEDS_CONTEXT=&amp;#39;${{ toJson(needs) }}&amp;#39;
          echo &amp;quot;$NEEDS_CONTEXT&amp;quot; | jq -e &amp;#39;all(.result == &amp;quot;success&amp;quot;)&amp;#39; || {
            echo &amp;quot;::error::One or more security scans failed&amp;quot;
            exit 1
          }

          echo &amp;quot;✓ All security gates passed&amp;quot;

  # Security: Production deployment (manual approval)
  deploy_production:
    name: Deploy to Production
    runs-on: ubuntu-latest
    needs: security_gate
    if: github.ref == &amp;#39;refs/heads/main&amp;#39;
    timeout-minutes: 30
    environment:
      name: production
      url: https://example.com

    steps:
      - name: Download Docker Image
        uses: actions/download-artifact@v4
        with:
          name: docker-image-${{ github.run_number }}

      - name: Load and Deploy Image
        run: |
          set -euo pipefail

          docker load &amp;lt; myapp.tar.gz

          echo &amp;quot;Deploying to production...&amp;quot;
          # Your production deployment commands here

          echo &amp;quot;✓ Production deployment completed&amp;quot;

      # Security: Post-deployment verification
      - name: Verify Production Deployment
        run: |
          set -euo pipefail

          echo &amp;quot;Verifying production deployment...&amp;quot;

          MAX_RETRIES=30
          for i in $(seq 1 $MAX_RETRIES); do
            if curl -sSf &amp;quot;https://example.com/health&amp;quot;; then
              echo &amp;quot;✓ Production deployment verified&amp;quot;
              exit 0
            fi
            sleep 10
          done

          echo &amp;quot;::error::Production verification failed&amp;quot;
          exit 1

  # Security: Notification and cleanup
  notify:
    name: Notify Security Team
    runs-on: ubuntu-latest
    needs: [deploy_production]
    if: always()

    steps:
      - name: Send Notification
        run: |
          echo &amp;quot;Security pipeline completed&amp;quot;
          echo &amp;quot;Status: ${{ job.status }}&amp;quot;
          # Add notification logic (Slack, email, etc.)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This pipeline runs SAST and SCA in parallel first (fast feedback), then builds and scans the container, deploys to staging, runs DAST, and only deploys to production if everything passes. It&amp;#39;s a complete shift-left security implementation.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions About Shift-Left Security and CI/CD Integration&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What&amp;#39;s the difference between shift-left testing and shift-left security?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Shift-left testing is about moving all types of testing (functional, performance, etc.) earlier in the development cycle to catch bugs sooner and improve software quality. Shift-left security specifically focuses on integrating security practices and testing (&lt;strong&gt;SAST&lt;/strong&gt;, &lt;strong&gt;DAST&lt;/strong&gt;, &lt;strong&gt;SCA&lt;/strong&gt;) from the earliest stages of development. While shift-left testing aims to improve overall quality, shift-left security targets security vulnerabilities specifically. The key difference? Security becomes a first-class concern from day one, not something you bolt on at the end.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How far left should security be shifted?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;As far left as possible. Ideally, security should be part of every stage of your software development lifecycle, starting from initial planning and requirements gathering. This includes defining security requirements upfront, considering security in your design, using secure coding practices during development, and continuously testing throughout the build and release process. The goal is to make security a fundamental part of how you build software, not an afterthought.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the key principles of shift-left security?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Shift-left security boils down to a few core principles: integrate security into every SDLC stage starting with design; automate security testing as much as possible, especially in CI/CD pipelines; foster collaboration and shared responsibility between dev, security, and ops teams (DevSecOps); empower developers with training and tools to write secure code; continuously monitor and get feedback to improve security; and establish clear security policies so developers know what&amp;#39;s expected. The main goal is making security proactive and built-in, not reactive and tacked-on.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the benefits of integrating security testing in CI/CD?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Integrating security testing (&lt;strong&gt;SAST&lt;/strong&gt;, &lt;strong&gt;DAST&lt;/strong&gt;, &lt;strong&gt;SCA&lt;/strong&gt;) into CI/CD gives you tons of benefits. You catch vulnerabilities early when they&amp;#39;re cheap and easy to fix. Automation ensures consistent security checks with every code change, reducing human error and preventing security from becoming a bottleneck. Early feedback helps developers learn secure coding practices and improves overall code quality. It speeds up releases by preventing last-minute security fire drills. You get a more secure software supply chain by identifying third-party component vulnerabilities. Automated checks help meet compliance requirements. Continuous monitoring with immediate feedback makes your applications significantly more secure overall.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the challenges of integrating security testing in CI/CD?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Integrating security into CI/CD pipelines comes with challenges. It can make your pipeline more complex as you add different security checks. There&amp;#39;s a risk of slowing down release velocity if security testing isn&amp;#39;t optimized. Comprehensive application security means adding various test types, which adds complexity. Sometimes security tools don&amp;#39;t integrate well with each other or your CI/CD platform. Managing the increased volume of alerts and false positives can overwhelm developers. Ensuring consistent security practices across different environments (dev, staging, prod) is hard. You might have gaps from incomplete testing or outdated pipelines. Scaling the pipeline to handle additional security checks without performance degradation requires planning. And you&amp;#39;ll face developer resistance if they perceive it as slowing them down.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How often should you run SAST/DAST/SCA?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;It depends on your development velocity, application criticality, and risk tolerance. &lt;strong&gt;SAST&lt;/strong&gt; and &lt;strong&gt;SCA&lt;/strong&gt; should run in your CI process, ideally on every commit or merge to give developers immediate feedback. Daily scans or scans with every significant code change catch issues early. &lt;strong&gt;DAST&lt;/strong&gt; scans need a running application, so they typically run after deployment to staging or test environments. How often you run &lt;strong&gt;DAST&lt;/strong&gt; varies, but common practice is with each staging deployment or on a regular schedule (weekly or nightly). For production apps, occasional &lt;strong&gt;DAST&lt;/strong&gt; scans are good, but be careful not to disrupt availability. &lt;strong&gt;SCA&lt;/strong&gt; should run frequently, ideally with every build or dependency update, because new vulnerabilities are constantly discovered in third-party libraries. Continuous monitoring for new vulnerabilities in your dependencies is a best practice so you can react quickly to emerging threats.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some best practices for implementing SAST/DAST/SCA in CI/CD?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Best practices include establishing clear security policies; automating all three security testing types in your pipeline; providing developers with training and resources on secure coding and tool usage; fostering collaboration between dev, security, and ops teams; prioritizing and remediating findings based on risk; keeping tools and dependencies updated; and having clear remediation workflows. Configure tools to minimize false positives, make security a shared responsibility, and continuously monitor and improve your practices. Start with security requirements early and add security to code reviews.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can developers overcome resistance to shift-left security?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Overcoming developer resistance requires training and resources so they understand security best practices and know how to use the tools. Integrate security tools seamlessly with their existing workflows (IDEs, version control) to minimize disruption. Configure tools to reduce false positives and provide clear, actionable remediation guidance instead of just dumping alerts on them. Emphasize that security is a shared responsibility and foster collaboration between dev, security, and ops so developers feel supported rather than burdened. Highlight the benefits: less rework, faster releases, better code quality. When developers see the value, they&amp;#39;re more likely to embrace it.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can organizations address alert fatigue in shift-left security?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tackling alert fatigue is crucial for shift-left success. Configure security tools to significantly reduce false positives and low-priority alerts. Prioritize alerts by severity so developers focus on critical issues first, not a massive list. Provide clear, actionable remediation guidance directly in the tools developers use. Consolidate security tools and dashboards for a unified view of findings. Use AI-powered tools that intelligently filter and prioritize based on context and impact. Establish clear SLAs for vulnerability remediation and give developers time and resources to address issues, preventing alert backlog and the feeling of being overwhelmed.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Integrating shift-left security into your development workflow, especially by using &lt;strong&gt;SAST&lt;/strong&gt;, &lt;strong&gt;DAST&lt;/strong&gt;, and &lt;strong&gt;SCA&lt;/strong&gt; in CI/CD pipelines, isn&amp;#39;t optional anymore. In today&amp;#39;s threat landscape, it&amp;#39;s essential. By thinking about security from the start, you&amp;#39;ll save money, ship faster, build more secure applications, and develop security-aware teams.&lt;/p&gt;
&lt;p&gt;Yes, implementation has challenges: resistance to change, alert fatigue, tooling complexity. But the best practices we&amp;#39;ve covered (automation, developer training, cross-team collaboration) will get you there. Tools like &lt;strong&gt;SonarQube&lt;/strong&gt;, &lt;strong&gt;OWASP ZAP&lt;/strong&gt;, and &lt;strong&gt;Trivy&lt;/strong&gt; make security a natural part of how you build software, not a painful add-on. The result? Safer, more reliable applications and fewer 3 AM security incidents.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.crowdstrike.com/en-us/cybersecurity-101/cloud-security/shift-left-security/&quot;&gt;What is Shift Left? Security, Testing &amp;amp; More Explained | CrowdStrike&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.checkpoint.com/cyber-hub/cloud-security/what-is-shift-left-security/&quot;&gt;Shift Left Security Explained: Key Concepts and Benefits - Check Point Software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.perforce.com/blog/sca/what-is-shift-left-security&quot;&gt;What is Shift Left Security? | Perforce Software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.stackhawk.com/blog/why-shift-security-left/&quot;&gt;Shifting Security Left: Benefits &amp;amp; Implementation Tips - StackHawk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.codacy.com/what-is-shift-left-security&quot;&gt;Shift Left Security: A Complete Guide - Codacy | Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.stackhawk.com/blog/the-appsec-guide-to-shift-left-security-how-to-integrate-security-earlier-in-the-sdlc/&quot;&gt;The AppSec Guide to Shift-Left Security: How to Integrate Security Earlier in the SDLC - StackHawk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.harness.io/harness-devops-academy/what-is-shift-left-security&quot;&gt;What is Shift-left Security? | Harness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://snyk.io/articles/shift-left-security/&quot;&gt;Implementing Shift Left Security Effectively - Snyk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.blackduck.com/glossary/what-is-software-composition-analysis.html&quot;&gt;What is Software Composition Analysis (SCA)? | Black Duck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://owasp.org/www-community/Source_Code_Analysis_Tools&quot;&gt;Source Code Analysis Tools - OWASP Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://owasp.org/www-project-devsecops-guideline/latest/02b-Dynamic-Application-Security-Testing&quot;&gt;Dynamic Application Security Testing (DAST) - OWASP DevSecOps Guideline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://trivy.dev/v0.40/ecosystem/cicd/&quot;&gt;CI/CD Integrations - Trivy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://appcircle.io/blog/how-to-integrate-sonarqube-into-your-ci-cd-workflow&quot;&gt;A Step-by-Step Guide to Integrating SonarQube into Your CI/CD Workflow - Appcircle Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.clovinsec.com/post/ultimate-guide-to-owasp-zap-understanding-the-architecture-implementing-ci-cd-and-best-practices&quot;&gt;Ultimate Guide to OWASP ZAP: Understanding the Architecture, Implementing CI/CD, and Best Practices - Clovin Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://digital.ai/glossary/shift-left-security/&quot;&gt;Shift Left Security: Principles and Best Practices | Digital.ai&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>CI/CD</category><category>DevSecOps</category><category>Security</category><category>Automation</category><category>Application Security</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0092-shift-left-security-sast-dast-sca-cicd/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Container Image Signing with Cosign: A Hands-On Guide to Secure Your Supply Chain</title><link>https://mkabumattar.com/blog/post/container-image-signing-cosign-guide/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/container-image-signing-cosign-guide/</guid><description>Secure your software supply chain with Cosign. This hands-on guide covers container image signing, keyless and KMS methods, CI/CD automation, Kubernetes deployment verification, and advanced security best practices.</description><pubDate>Sun, 18 Jan 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In today&amp;#39;s fast-paced software world, we all rely on container images to package and run our apps. They&amp;#39;re super consistent and efficient, which is great! But this ease also brings new security headaches. We really need to make sure the images running in production are exactly what we expect and haven&amp;#39;t been messed with. That&amp;#39;s where &lt;strong&gt;Cosign&lt;/strong&gt; comes in. It&amp;#39;s a powerful open-source tool that helps us sign and verify our container images, making our software supply chain much safer.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why Should You Sign Your Container Images?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Container images are like the basic building blocks for today&amp;#39;s apps. They let us package and run software the same way everywhere, without worrying about different setups or dependencies. That consistency is a huge plus, but it also brings some unique security questions.&lt;/p&gt;
&lt;p&gt;So, what&amp;#39;s container image signing? It&amp;#39;s basically putting a digital signature on a container image. Think of this signature as a cryptographic seal. It gives you strong proof that the image is real and hasn&amp;#39;t been changed. It confirms the image came from someone you trust and hasn&amp;#39;t been messed with since they signed it. It&amp;#39;s like giving the image a digital fingerprint that you can check later to make sure it&amp;#39;s good. When a developer signs an image with their private key, anyone who gets that image can use the matching public key to confirm it&amp;#39;s the original and where it came from. This is a really important step because it helps stop attacks, like someone trying to sneak bad images into your system. In the end, this digital signature acts as a key checkpoint when you&amp;#39;re putting things out there, making sure only images you&amp;#39;ve checked and trust actually run in your environment.&lt;/p&gt;
&lt;p&gt;The big problem container image signing solves goes beyond just general security. It&amp;#39;s about building a solid chain of trust and making sure you can actually verify where your software comes from in today&amp;#39;s complicated supply chains. If you pull an image from a registry without a signature, you really don&amp;#39;t know where it came from or what&amp;#39;s inside, so it&amp;#39;s hard to trust it. This missing proof of origin is a big risk, especially since modern container images often have many layers, with different teams or even outside sources adding to them. For real security, you need to trust every single layer of a container image. Signing gives you that cryptographic connection to check every step of an image&amp;#39;s path from where it started to where it finally runs. This makes the whole process clear and safe. So, image signing isn&amp;#39;t just a nice-to-have security feature; it&amp;#39;s a basic must-have for keeping your software supply chain honest and secure.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Why is Cosign the best tool for this?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Cosign&lt;/strong&gt; is an open-source tool you run from your command line, and it&amp;#39;s a big part of the larger Sigstore project. Sigstore itself is a non-profit public service, and its main goal is to make software signing easier and safer for everyone.&lt;/p&gt;
&lt;p&gt;Cosign&amp;#39;s main idea is to make signatures &amp;quot;invisible to infrastructure.&amp;quot; What that means is the tool tries to make the whole signing and checking process super simple, hiding most of the tricky parts you usually deal with when it comes to digital signatures. Instead of needing separate, complicated systems to keep signatures, Cosign puts them right next to your container image in the Open Container Initiative (OCI) registry. This built-in way of doing things really cuts down on the work you have to do.&lt;/p&gt;
&lt;p&gt;Since Cosign is a core part of the Sigstore world, it gets to use Sigstore&amp;#39;s free Certificate Authority, Fulcio, and its public record book, Rekor. This combo is really powerful because it solves one of the toughest parts of signing software: how to safely give out and manage your signing keys. In the past, putting strong security features like digital signatures in place was hard. It often needed a lot of crypto knowledge and a ton of effort. But by making key management simpler and putting signature storage right into your current container registries, Cosign makes it much easier for developers and DevOps teams to get started. This focus on making things easy to use means you can fit these important security steps right into your existing development and &lt;strong&gt;deployment&lt;/strong&gt; routines. That&amp;#39;s why it&amp;#39;s a popular and practical choice for making your &lt;strong&gt;container security&lt;/strong&gt; better. This way of thinking is a big step toward security tools that developers actually like to use, which is key for getting security involved earlier in the development process.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Getting Started: How Do I Install Cosign?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Before you can sign and verify container images, you&amp;#39;ll need to get Cosign installed on your computer. It&amp;#39;s built to work with lots of different systems, so you&amp;#39;ve got a few ways to install it, and it plays nicely with common &lt;strong&gt;CI/CD&lt;/strong&gt; setups.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How do I install Cosign on different operating systems?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;If you&amp;#39;ve got Go (version 1.20 or newer) installed, the easiest way to get the latest Cosign directly from its source is to run this command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;go install github.com/sigstore/cosign/v2/cmd/cosign@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that&amp;#39;s done, you&amp;#39;ll find the Cosign program in your Go binary path, usually &lt;code&gt;$GOPATH/bin/cosign&lt;/code&gt; or &lt;code&gt;$GOBIN/cosign&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Or, you can just download ready-to-use programs for Linux, macOS, and Windows directly from the official Cosign releases page on GitHub. For instance, if you&amp;#39;re on a Linux AMD64 system, you can use these commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl -O -L &amp;quot;https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64&amp;quot;
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
sudo chmod +x /usr/local/bin/cosign
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you like using package managers, installing Cosign is a breeze:&lt;/p&gt;
&lt;Tabs&gt;
  &lt;Tab name=&quot;Homebrew&quot;&gt;
    #### Homebrew (macOS) / Linuxbrew (Linux)&lt;pre&gt;&lt;code&gt;Homebrew is the most popular package manager for macOS and also works on Linux. It maintains up-to-date packages and handles dependencies automatically. This is the recommended method for developers working on macOS or Linux with Homebrew already installed.

```shell title=&amp;quot;Install Cosign with Homebrew&amp;quot;
brew install cosign
```

After installation, Homebrew places the `cosign` binary in your PATH automatically, typically in `/usr/local/bin` or `/opt/homebrew/bin`.
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;  &lt;Tab name=&quot;Debian / Ubuntu&quot;&gt;
    #### Debian / Ubuntu&lt;pre&gt;&lt;code&gt;For Debian-based distributions like Debian, Ubuntu, Linux Mint, and Pop!_OS, you can download and install the `.deb` package directly from the official Cosign releases. This method works for both x86_64 and ARM64 architectures.

```shell title=&amp;quot;Install Cosign on Debian/Ubuntu (AMD64)&amp;quot;
curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign_amd64.deb
sudo dpkg -i cosign_amd64.deb
```

For ARM64 systems (like Raspberry Pi):

```shell title=&amp;quot;Install Cosign on Debian/Ubuntu (ARM64)&amp;quot;
curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign_arm64.deb
sudo dpkg -i cosign_arm64.deb
```

The `.deb` package installs Cosign to `/usr/bin/cosign` and is managed by your system&amp;#39;s package manager, making updates and removal straightforward.
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;  &lt;Tab name=&quot;Red Hat / CentOS&quot;&gt;
    #### Red Hat Enterprise Linux / CentOS&lt;pre&gt;&lt;code&gt;For RHEL, CentOS, and compatible distributions, Cosign provides `.rpm` packages. These work with both `yum` and `dnf` package managers and are available for x86_64 and ARM64 architectures.

```shell title=&amp;quot;Install Cosign on RHEL/CentOS (AMD64)&amp;quot;
curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign-amd64.rpm
sudo rpm -ivh cosign-amd64.rpm
```

For ARM64 systems:

```shell title=&amp;quot;Install Cosign on RHEL/CentOS (ARM64)&amp;quot;
curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign-arm64.rpm
sudo rpm -ivh cosign-arm64.rpm
```

The RPM package integrates with your system&amp;#39;s package management, allowing you to remove it later with `sudo rpm -e cosign` if needed.
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;  &lt;Tab name=&quot;Fedora&quot;&gt;
    #### Fedora&lt;pre&gt;&lt;code&gt;Fedora users can install Cosign using the `.rpm` package with `dnf`, Fedora&amp;#39;s modern package manager. The process is similar to RHEL/CentOS but optimized for Fedora&amp;#39;s faster release cycle.

```shell title=&amp;quot;Install Cosign on Fedora (AMD64)&amp;quot;
curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign-amd64.rpm
sudo dnf install cosign-amd64.rpm
```

For ARM64 systems:

```shell title=&amp;quot;Install Cosign on Fedora (ARM64)&amp;quot;
curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign-arm64.rpm
sudo dnf install cosign-arm64.rpm
```

Using `dnf install` instead of `rpm -ivh` allows dnf to automatically handle any dependencies if they&amp;#39;re needed in future versions.
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;  &lt;Tab name=&quot;Arch Linux&quot;&gt;
    #### Arch Linux&lt;pre&gt;&lt;code&gt;Arch Linux users can install Cosign directly from the official repositories using pacman. The Arch package is maintained by the community and stays current with upstream releases.

```shell title=&amp;quot;Install Cosign on Arch Linux&amp;quot;
sudo pacman -S cosign
```

This installs Cosign system-wide and makes it immediately available in your shell. You can also check for updates using `sudo pacman -Syu`.
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;  &lt;Tab name=&quot;Alpine Linux&quot;&gt;
    #### Alpine Linux&lt;pre&gt;&lt;code&gt;Alpine Linux is commonly used in container images due to its minimal size. Cosign is available in Alpine&amp;#39;s package repositories, making it perfect for lightweight container-based signing workflows.

```shell title=&amp;quot;Install Cosign on Alpine Linux&amp;quot;
apk add cosign
```

This is particularly useful when building CI/CD pipeline containers where you need Cosign available but want to keep the image size small. Alpine&amp;#39;s `apk` package manager downloads and installs efficiently.
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;  &lt;Tab name=&quot;Nix / NixOS&quot;&gt;
    #### Nix / NixOS&lt;pre&gt;&lt;code&gt;Nix is a powerful, declarative package manager that works on Linux and macOS. It provides reproducible builds and allows you to install packages without affecting your system state. Perfect for developers who need isolated, reproducible environments.

```shell title=&amp;quot;Install Cosign with Nix&amp;quot;
nix-env -iA nixpkgs.cosign
```

Nix packages are fully isolated and can coexist with other versions. You can also add Cosign to your NixOS system configuration or development shells declaratively.
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;  &lt;Tab name=&quot;Windows&quot;&gt;
    #### Windows&lt;pre&gt;&lt;code&gt;Windows users can install Cosign using Scoop, a command-line installer, or by downloading the binary directly. Scoop is recommended as it handles PATH configuration automatically.

**Chocolatey:**

```powershell title=&amp;quot;Install Cosign with Chocolatey&amp;quot;
choco install cosign
```

**Using Scoop:**

```powershell title=&amp;quot;Install Cosign with Scoop&amp;quot;
scoop install cosign
```

**Manual Installation:**

Download the Windows binary and add it to your PATH:

```powershell title=&amp;quot;Manual Install on Windows&amp;quot;
curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign-windows-amd64.exe
Move-Item .\cosign-windows-amd64.exe C:\Windows\System32\cosign.exe
```

After installation, open a new PowerShell or Command Prompt window and verify with `cosign version`.
&lt;/code&gt;&lt;/pre&gt;
  &lt;/Tab&gt;
&lt;/Tabs&gt;&lt;p&gt;Cosign is also built for automated tasks, and it works directly with popular CI/CD platforms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub Actions:&lt;/strong&gt; The &lt;code&gt;sigstore/cosign-installer@main&lt;/code&gt; GitHub Action makes installing Cosign in a workflow simple. You can even pick a specific Cosign release version if you need to.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitLab CI:&lt;/strong&gt; In GitLab CI jobs, you can install Cosign in the &lt;code&gt;before_script&lt;/code&gt; section, often using &lt;code&gt;apk add --update cosign&lt;/code&gt; for Alpine-based runners.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For container setups, you can even find signed release images of Cosign itself at &lt;code&gt;ghcr.io/sigstore/cosign/cosign&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How can I quickly check if Cosign is installed?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To make sure it&amp;#39;s installed correctly, just type &lt;code&gt;cosign version&lt;/code&gt; in your terminal. You should see something like this, telling you Cosign is good to go:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ cosign version
cosign: A tool for Container Signing, Verification and Storage in an OCI registry.
GitVersion: 1.13.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s something important, but often missed, about &lt;strong&gt;supply chain security&lt;/strong&gt;: you need to trust the tools you&amp;#39;re using to secure everything else. The Sigstore project takes this seriously. They sign Cosign&amp;#39;s own programs using both keyless signing and an artifact key. Before you even start using Cosign, it&amp;#39;s a good idea to check its authenticity with The Update Framework (TUF). This is a great example of a &amp;quot;security-in-depth&amp;quot; approach, meaning we&amp;#39;re applying the same trust principles to the tools that help us verify things. It shows you need to be careful at every step of the software supply chain, even with the security tools themselves. This dedication to making sure its own distribution is safe sets a high bar and reinforces the idea that supply chain security is a problem that keeps on giving, needing attention at every level, from your app&amp;#39;s code to the tools you use to build and deploy it.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Signing Your Images: How Do I Secure My Containers with Cosign?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Now that Cosign&amp;#39;s installed, it&amp;#39;s time to actually secure your container images by signing them. Cosign gives you a few different ways to sign, so you can pick what works best for your security needs and how you operate.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How do I use key-based signing?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This is a more traditional way of doing things. You use a private/public key pair. Your private key stays secret and you use it to create the digital signature. Then, you share the public key so others can check that signature.&lt;/p&gt;
&lt;p&gt;To make these key pairs, Cosign has a simple command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign generate-key-pair
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will ask you to set a password to protect your private key. Then, it creates two files: &lt;code&gt;cosign.key&lt;/code&gt; (that&amp;#39;s your private key) and &lt;code&gt;cosign.pub&lt;/code&gt; (that&amp;#39;s the public one). It&amp;#39;s super important to guard that private key carefully. You should keep its password in a secure manager, like HashiCorp Vault or AWS KMS.&lt;/p&gt;
&lt;p&gt;Once you&amp;#39;ve got your key pair, you can sign an image using your private key:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign sign --key cosign.key your-registry.com/your-image:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cosign will ask for the password you set when you made the keys. The signature it creates then goes right into your OCI registry, next to the image. It usually shows up as a new tag that includes the image&amp;#39;s digest (like &lt;code&gt;your-registry.com/your-image@sha256:abc...def.sig&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;While this works, key-based signing brings some real challenges for operations and security. The biggest worry is keeping that private key safe: how do you store it, get it to your signing systems (like CI/CD agents), and change it regularly without someone getting their hands on it? If a private key gets stolen, an attacker could sign bad images that look legitimate, totally breaking your trust system. This difficulty with key management is a big reason why we&amp;#39;re seeing more advanced, &amp;quot;keyless&amp;quot; signing methods. The actual signing part is easy, but keeping long-lived private keys secure is a huge job and a major way attackers can get in with traditional security. This really shows why we need ways to make key management easier or even get rid of it entirely, which is exactly what keyless signing tries to do.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What&amp;#39;s keyless signing and how does it work with Sigstore, OIDC, Fulcio, and Rekor?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Keyless signing is Cosign&amp;#39;s standout feature, and it&amp;#39;s what we usually suggest for most situations. This game-changing method means you don&amp;#39;t have to deal with long-lasting private keys anymore. Instead, it uses your existing identities, like your Google, GitHub, or Microsoft accounts, to create temporary signing keys that only stick around for a short time.&lt;/p&gt;
&lt;p&gt;The whole process, often called the Sigstore Flow, works like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Temporary Key Creation:&lt;/strong&gt; When you run &lt;code&gt;cosign sign&lt;/code&gt; in keyless mode, Cosign first makes a temporary public/private key pair in your computer&amp;#39;s memory. This key pair is only around for that one signing job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identity Check (Fulcio):&lt;/strong&gt; Cosign then asks you to log in with an OpenID Connect (OIDC) provider, like Google, GitHub, Microsoft, or GitLab. It sends a Certificate Signing Request (CSR) and your OIDC identity token to Fulcio, which is Sigstore&amp;#39;s free, public Certificate Authority. Fulcio checks your identity and then gives you a short-lived X.509 certificate, usually good for only about 10 minutes. This certificate cryptographically links that temporary public key to your confirmed OIDC identity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Signing &amp;amp; Key Deletion:&lt;/strong&gt; Cosign goes ahead and signs the container image using that temporary private key. Here&amp;#39;s the important part: right after it&amp;#39;s done signing, that private key is completely wiped out and never saved anywhere. This dramatically lowers the chance of someone stealing your key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Public Record (Rekor):&lt;/strong&gt; Cosign then writes down the signature, the short-lived certificate, and other important details, like the image&amp;#39;s digest, in Rekor. Rekor is Sigstore&amp;#39;s public, tamper-proof record book. This record gives you a permanent, auditable history of every signing event, so you can keep an eye out for anything suspicious.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upload:&lt;/strong&gt; Finally, the signature, the certificate, and proof that it&amp;#39;s in Rekor all get uploaded to the OCI registry, right next to your container image.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The command to sign using this method is pretty simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign sign your-registry.com/your-image:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In automated setups, like a CI/CD pipeline, Cosign can often figure out the OIDC issuer (like GitHub or GitLab) on its own and handle logging in without you needing to do anything.15 For example, in GitLab CI, you&amp;#39;d set the &lt;code&gt;SIGSTORE_ID_TOKEN&lt;/code&gt; environment variable with the &lt;code&gt;aud: sigstore&lt;/code&gt; claim.&lt;/p&gt;
&lt;p&gt;Keyless signing directly solves that &amp;quot;key management problem&amp;quot; you get with older signing methods. By using temporary keys and connecting signatures to your existing OIDC identities, it really takes the pressure off developers who would otherwise have to keep sensitive private keys safe and sound. This way, there&amp;#39;s less for attackers to target, and it makes things much easier to run. The public record book (Rekor) makes it even stronger by giving you a permanent, auditable history of every signing event. That&amp;#39;s super important for spotting any unauthorized use of an identity, even if someone did manage to get in. This whole idea is a big step forward for software supply chain security. It moves us toward a more automated, identity-focused, and open way of doing things that deals with the real-world issues of traditional Public Key Infrastructure (PKI).&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How can I use Key Management Services (KMS) for better security?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;If your organization already has key management systems in place, strict compliance rules, or just prefers to keep keys in one central spot, Cosign works really well with different Key Management Service (KMS) providers. This means you can use keys backed by hardware or managed in the cloud for your signing tasks.&lt;/p&gt;
&lt;p&gt;Cosign supports big cloud KMS providers like AWS KMS, Google Cloud KMS, and Azure Key Vault, plus Hashicorp Vault and even &lt;strong&gt;Kubernetes&lt;/strong&gt; Secrets. When you&amp;#39;re using KMS, Cosign points to the key using a &lt;code&gt;go-cloud&lt;/code&gt; style URI. Here are some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS KMS: &lt;code&gt;awskms://$ENDPOINT/$KEYID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;GCP KMS: &lt;code&gt;gcpkms://projects/$PROJECT/locations/$LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY/versions/$KEY_VERSION&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Azure Key Vault: &lt;code&gt;azurekms:///[KEY]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Hashicorp Vault: &lt;code&gt;hashivault://$keyname&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes Secret: &lt;code&gt;k8s:///[NAME]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can even make keys right inside your KMS provider using Cosign:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign generate-key-pair --kms &amp;lt;some provider&amp;gt;://&amp;lt;some key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To sign an image with a key managed by KMS, you just pass the KMS URI to the &lt;code&gt;--key&lt;/code&gt; flag:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign sign --key &amp;lt;some provider&amp;gt;://&amp;lt;some key&amp;gt; $IMAGE_DIGEST
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s important to remember that the user or service account doing these things will need the right IAM roles and permissions within your specific KMS provider (for example, &lt;code&gt;Key Vault Crypto Officer&lt;/code&gt; to create keys, and &lt;code&gt;Key Vault Crypto User&lt;/code&gt; to sign in Azure Key Vault).&lt;/p&gt;
&lt;p&gt;KMS integration is super important for big companies to use Cosign. It lets them use their current security tools and meet tough compliance rules, like FIPS, SOC 2, or ISO 27001, which often say you have to use Hardware Security Modules (HSMs) or cloud-managed keys. While keyless signing is a great choice for many situations, KMS gives you the flexibility you need for highly regulated environments. It makes sure your signing keys are managed with the best security and audit trails possible. This feature connects modern security practices with the demands of running things at an enterprise level.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Why should I always sign image digests, not mutable tags?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This is a basic rule for &lt;strong&gt;container image security&lt;/strong&gt;. Tags (like &lt;code&gt;:latest&lt;/code&gt; or &lt;code&gt;:v1.0&lt;/code&gt;) are handy, but they can change. Someone could overwrite them to point to a totally different image without you knowing. If you sign a tag, and then that tag gets updated to point to a bad image, the original signature for the &lt;em&gt;old&lt;/em&gt; stuff doesn&amp;#39;t mean anything for the &lt;em&gt;new&lt;/em&gt; stuff anymore.&lt;/p&gt;
&lt;p&gt;Digests, on the other hand, never change. A digest (like &lt;code&gt;sha256:abcdef...&lt;/code&gt;) is a cryptographic hash that gives you a unique ID for the exact content of an image. It&amp;#39;s like a permanent, unchangeable fingerprint.&lt;/p&gt;
&lt;p&gt;So, the best advice is to always sign the image using its digest. This makes sure the signature is cryptographically tied to the exact, unchanging content of the image, creating a strong, verifiable link to where it came from. A good CI/CD pipeline should grab the image digest right after building and pushing the image, and then sign that specific digest.&lt;/p&gt;
&lt;p&gt;Signing image digests instead of those changeable tags is a really important practice. It directly tackles the main problem of making sure things can&amp;#39;t be changed and you can trace them precisely in your software supply chain. Tags can change, and that&amp;#39;s a known weak spot. An attacker could swap out a trusted image for a bad one using the same tag, getting past your basic trust checks. But by signing the digest, you create a link to the exact content that can&amp;#39;t be faked. This guarantees that the image you check is precisely what you wanted and stops supply chain attacks that try to trick you with changing tags. This just shows how important it is to understand how container registries really work and to make smart security choices that put immutability first, even if it means a little less convenience.&lt;/p&gt;
&lt;p&gt;Here is a summary of the key management options available with &lt;strong&gt;Cosign&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Method&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Example Command&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Key-based&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Traditional private/public key pair. Private key is stored locally.&lt;/td&gt;
&lt;td&gt;Full control over keys.&lt;/td&gt;
&lt;td&gt;Complex key management (storage, distribution, rotation); high risk if private key is compromised.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cosign sign --key cosign.key my-image@sha256:digest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Keyless (Sigstore)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Uses ephemeral keys and OIDC identities (Google, GitHub, Microsoft, GitLab) with Fulcio CA and Rekor transparency log.&lt;/td&gt;
&lt;td&gt;No long-lived keys to manage; uses existing identities; public auditability.&lt;/td&gt;
&lt;td&gt;Relies on Sigstore public infrastructure (or self-hosted); needs an OIDC provider.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cosign sign my-image@sha256:digest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;KMS (Key Management Service)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Works with cloud KMS (AWS, GCP, Azure), Hashicorp Vault, Kubernetes Secrets.&lt;/td&gt;
&lt;td&gt;Centralized, secure key management (often HSM-backed); meets compliance needs.&lt;/td&gt;
&lt;td&gt;Adds cloud provider dependency; needs specific IAM permissions.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cosign sign --key gcpkms://... my-image@sha256:digest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Verifying Trust: How Do I Validate Signed Container Images?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Signing images is just one piece of the security puzzle. The real power of &lt;strong&gt;image signing&lt;/strong&gt; comes from being able to check those signatures. This vital step makes sure that any image you put out there is truly authentic and hasn&amp;#39;t been messed with.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How do I verify images with public keys?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The most common way to check a signed image is by using the public key that goes with the private key used for signing. The basic command for this is pretty simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign verify [--key &amp;lt;key path&amp;gt;|&amp;lt;key url&amp;gt;|&amp;lt;kms uri&amp;gt;] &amp;lt;image uri&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the person who signed it gave you their &lt;code&gt;cosign.pub&lt;/code&gt; file, you can check the image using a public key right there on your computer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign verify --key cosign.pub your-registry.com/your-image@sha256:digest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have a signed image stored locally, like in an air-gapped setup, you can check it without an internet connection:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign verify --key cosign.pub --local-image PATH/to/your/image
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the image was signed with a key from a KMS, you can check it by just pointing to the KMS URI, assuming you have the right permissions to get to the public key:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign verify --key &amp;lt;some provider&amp;gt;://&amp;lt;some key&amp;gt; your-registry.com/your-image@sha256:digest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, you can pull the public key out of the KMS and use it as a local file to check.22 Cosign even lets multiple people sign one image. When you run &lt;code&gt;cosign verify&lt;/code&gt;, it checks all the signatures attached, making sure everyone who needed to approve the image did.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What&amp;#39;s keyless verification and how does it work?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Keyless verification is a really cool part of Cosign. It changes how we think about trust, moving from fixed keys to identities you can actually verify. This method works especially well in automated setups.&lt;/p&gt;
&lt;p&gt;For identity-based checks, instead of giving it a public key file, you tell it the signer&amp;#39;s expected identity and their OIDC issuer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign verify your-registry.com/your-image@sha256:digest \
  --certificate-identity=name@example.com \
  --certificate-oidc-issuer=https://accounts.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cosign works with popular OIDC providers, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google: &lt;code&gt;https://accounts.google.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Microsoft: &lt;code&gt;https://login.microsoftonline.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;code&gt;https://github.com/login/oauth&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;GitLab: &lt;code&gt;https://gitlab.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Behind the scenes, when you start a keyless &lt;strong&gt;verification&lt;/strong&gt;, Cosign does a few important things: it gets the signature and certificate from the OCI registry, cryptographically checks the signature, compares the signing event with Rekor (that public record book) to confirm it&amp;#39;s there, and then finally makes sure the identity in the certificate matches what you told it in the command.&lt;/p&gt;
&lt;p&gt;For things that aren&amp;#39;t container images (like plain files, or &amp;quot;blobs&amp;quot;), the signature and certificate can be put together into one file (&lt;code&gt;cosign.bundle&lt;/code&gt;) when you sign it. You can then use this bundle to check it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign verify-blob my-file.txt --bundle cosign.bundle \
  --certificate-identity=name@example.com \
  --certificate-oidc-issuer=https://accounts.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For container images, this bundle info is automatically included by default when you use keyless signing.&lt;/p&gt;
&lt;p&gt;Keyless verification is a big step forward in how we build trust in software. It moves past the complicated and error-prone job of safely giving out and managing fixed public keys. Instead, it uses existing, strong OIDC identity providers. This makes checking things easier for users because they can rely on a well-known identity provider instead of a specific key file. Adding the Rekor public record book makes it even stronger by giving you a permanent, publicly auditable record that the signing event happened. This adds another layer of proof and trust. This change makes &lt;strong&gt;verification&lt;/strong&gt; easier to scale and more user-friendly, taking some of the load off users and making security more available across big software systems by using identity setups that are already there.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How do attestations add more trust with SBOMs and vulnerability scans?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Beyond just checking if an image is intact, Cosign lets you verify &amp;quot;attestations.&amp;quot; These are signed bits of information about an artifact, giving you detailed, verifiable facts about what&amp;#39;s inside, how it was built, and its security status. They usually follow the in-toto format, which is a well-known standard for keeping software supply chains open and clear.&lt;/p&gt;
&lt;p&gt;Common types of attestations you&amp;#39;ll see are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Software Bill of Materials (SBOMs):&lt;/strong&gt; This is a full, detailed list of all open-source and commercial parts, libraries, and dependencies packed into an image.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vulnerability Scans:&lt;/strong&gt; These are records showing the results of security checks run on the image.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build Provenance:&lt;/strong&gt; Specifics about how, when, and by whom the image was built.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can check attestations using the &lt;code&gt;cosign verify-attestation&lt;/code&gt; command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign verify-attestation your-registry.com/your-image@sha256:digest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also check against a public key or by telling it the attestation type (for example, &lt;code&gt;--type https://spdx.dev/Document&lt;/code&gt; for SPDX SBOMs).&lt;/p&gt;
&lt;p&gt;If you want to look at the raw attestation data, you can download it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign download attestation --predicate-type=https://spdx.dev/Document your-registry.com/your-image@sha256:digest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s a practical example: making and checking an SBOM attestation with Trivy:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make an SBOM:&lt;/strong&gt; Use a tool like Trivy to create an SBOM for your image in a format it understands (like SPDX or CycloneDX):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;trivy image --format spdx -o sbom.spdx your-registry.com/your-image:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create Attestation:&lt;/strong&gt; Sign the SBOM and attach it to the image as an attestation. If you&amp;#39;re using key-based signing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign attest --key cosign.key --type spdx --predicate sbom.spdx your-registry.com/your-image@sha256:digest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For keyless signing, use &lt;code&gt;COSIGN_EXPERIMENTAL=1&lt;/code&gt; because this feature is still being worked on:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;COSIGN_EXPERIMENTAL=1 cosign attest --type spdx --predicate sbom.spdx your-registry.com/your-image@sha256:digest
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check Attestation:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cosign verify-attestation --key cosign.pub --type spdx your-registry.com/your-image@sha256:digest
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Attestations, especially SBOMs, take container security way beyond just checking if something&amp;#39;s been tampered with. They give you detailed, verifiable insights into what&amp;#39;s inside your software and where it came from. This is super important for &amp;quot;shift-left security,&amp;quot; which means finding and fixing security holes much earlier in the development process. Plus, with more and more rules and government orders, like the US Executive Order on Cybersecurity, SBOMs and verifiable attestations are becoming essential for showing you&amp;#39;re compliant and doing your homework in the software supply chain. They help users make truly informed choices about the software they run, giving them info not just about whether an image was signed, but also about what&amp;#39;s actually in it. Attestations are a key part of a solid software supply chain security plan, helping organizations understand, handle, and talk about the risks that come with their software dependencies more effectively.&lt;/p&gt;
&lt;p&gt;Here is a summary of key attestation types supported by &lt;strong&gt;Cosign&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Attestation Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Predicate Type URL&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Example Use Case&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Software Bill of Materials (SBOM)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://spdx.dev/Document&lt;/code&gt; or &lt;code&gt;https://cyclonedx.org/schema&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A full list of all software components, libraries, and dependencies.&lt;/td&gt;
&lt;td&gt;Good for vulnerability management, license compliance.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vulnerability Scan Record&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://cosign.sigstore.dev/attestation/vuln/v1&lt;/code&gt; (or custom)&lt;/td&gt;
&lt;td&gt;A record of known vulnerabilities found in the image.&lt;/td&gt;
&lt;td&gt;Good for making sure images meet security standards before deployment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Build Provenance (in-toto)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://in-toto.io/Statement/v0.1&lt;/code&gt; (or specific build system predicate)&lt;/td&gt;
&lt;td&gt;Details about how the image was built, including source code, build environment, and steps.&lt;/td&gt;
&lt;td&gt;Good for checking the integrity of the build process itself.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Automating Security: How Does Cosign Fit into My CI/CD Pipeline?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Putting Cosign into your Continuous Integration/Continuous Delivery (&lt;strong&gt;CI/CD&lt;/strong&gt;) pipeline is where &lt;strong&gt;container image signing&lt;/strong&gt; really gets automated and can grow with you. This &amp;quot;shift-left&amp;quot; idea means &lt;strong&gt;container security&lt;/strong&gt; becomes a natural part of your development process right from the start.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How do I integrate Cosign with GitHub Actions for easy signing?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitHub Actions is a popular platform for automating tasks, especially for projects on GitHub. Cosign works perfectly with it.&lt;/p&gt;
&lt;p&gt;Getting Cosign installed in a GitHub Actions workflow is easy thanks to the &lt;code&gt;sigstore/cosign-installer@main&lt;/code&gt; GitHub Action. You can just add it as a step in your workflow, and you can even pick a specific Cosign version if you need to.&lt;/p&gt;
&lt;p&gt;GitHub Actions is a great fit for keyless signing. Your workflow can automatically create an OIDC token that Cosign uses to prove its identity to Sigstore&amp;#39;s Fulcio CA. For this to happen, your workflow needs to have id-token: write permissions set up.&lt;/p&gt;
&lt;p&gt;Here is an example GitHub Actions workflow snippet showing the process:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Build and Sign Container Image

on:
  push:
    branches:
      - main

jobs:
  build-and-sign:
    runs-on: ubuntu-latest
    permissions:
      contents: read # To checkout code
      packages: write # To push images to GitHub Packages
      id-token: write # Required for keyless signing with GitHub OIDC Token
    steps:
      - uses: actions/checkout@v4
      - name: Install Cosign
        uses: sigstore/cosign-installer@v3.8.1 # Or @main for latest
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push image
        id: push
        uses: docker/build-push-action@v5
        with:
          context:.
          push: true
          tags: ghcr.io/${{ github.repository }}:latest
      - name: Sign the container image
        run: |
          cosign sign --yes ghcr.io/${{ github.repository }}@${{ steps.push.outputs.digest }} \
            --annotations &amp;quot;com.github.workflow=${{ github.workflow }}&amp;quot; \
            --annotations &amp;quot;com.github.run_id=${{ github.run_id }}&amp;quot;
      - name: Verify the signed image
        run: |
          cosign verify ghcr.io/${{ github.repository }}@${{ steps.push.outputs.digest }} \
            --certificate-identity &amp;quot;https://github.com/${{ github.repository }}/.github/workflows/main.yml@refs/heads/main&amp;quot; \
            --certificate-oidc-issuer &amp;quot;https://token.actions.githubusercontent.com&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;How do I automate image signing in GitLab CI?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitLab CI/CD is really tied into GitLab repositories, so it&amp;#39;s another fantastic place to automate image signing.&lt;/p&gt;
&lt;p&gt;You can also use GitLab ID tokens for keyless signing with Cosign. You&amp;#39;ll need to set up the &lt;code&gt;id_tokens&lt;/code&gt; section in your &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file to have the &lt;code&gt;aud&lt;/code&gt; claim as &lt;code&gt;sigstore&lt;/code&gt;. Cosign will then find and use this token on its own.&lt;/p&gt;
&lt;p&gt;Here is an example GitLab CI/CD &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;stages:
  - build
  - sign
  - verify

variables:
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA
  IMAGE_URI: $CI_REGISTRY_IMAGE:$IMAGE_TAG
  COSIGN_YES: &amp;#39;true&amp;#39; # Auto-confirm Cosign actions

build_and_push:
  stage: build
  image: docker:latest
  services:
    - docker:dind # Enable Docker-in-Docker
  script:
    - apk add --no-cache cosign jq # Install Cosign and jq
    - docker login -u &amp;quot;gitlab-ci-token&amp;quot; -p &amp;quot;$CI_JOB_TOKEN&amp;quot; &amp;quot;$CI_REGISTRY&amp;quot;
    - docker build -t &amp;quot;$IMAGE_URI&amp;quot;.
    - docker push &amp;quot;$IMAGE_URI&amp;quot;
    - IMAGE_DIGEST=$(docker inspect --format=&amp;#39;{{index.RepoDigests 0}}&amp;#39; &amp;quot;$IMAGE_URI&amp;quot;)
    - echo &amp;quot;IMAGE_DIGEST=$IMAGE_DIGEST&amp;quot; &amp;gt;&amp;gt; build.env
  artifacts:
    reports:
      dotenv: build.env

sign_image:
  stage: sign
  image: docker:latest
  services:
    - docker:dind
  needs:
    - job: build_and_push
      artifacts: true
  id_tokens:
    SIGSTORE_ID_TOKEN:
      aud: sigstore # Provide OIDC token for keyless signing
  script:
    - apk add --no-cache cosign jq
    - docker login -u &amp;quot;gitlab-ci-token&amp;quot; -p &amp;quot;$CI_JOB_TOKEN&amp;quot; &amp;quot;$CI_REGISTRY&amp;quot;
    - cosign sign &amp;quot;$IMAGE_DIGEST&amp;quot; \
      --annotations &amp;quot;com.gitlab.ci.user.name=$GITLAB_USER_NAME&amp;quot; \
      --annotations &amp;quot;com.gitlab.ci.pipeline.id=$CI_PIPELINE_ID&amp;quot; \
      --annotations &amp;quot;com.gitlab.ci.job.id=$CI_JOB_ID&amp;quot; \
      --annotations &amp;quot;tag=$IMAGE_TAG&amp;quot;

verify_image:
  stage: verify
  image: docker:latest
  services:
    - docker:dind
  needs:
    - job: sign_image
      artifacts: true
  script:
    - apk add --no-cache cosign jq
    - docker login -u &amp;quot;gitlab-ci-token&amp;quot; -p &amp;quot;$CI_JOB_TOKEN&amp;quot; &amp;quot;$CI_REGISTRY&amp;quot;
    - cosign verify &amp;quot;$IMAGE_URI&amp;quot; \
      --annotations &amp;quot;tag=$IMAGE_TAG&amp;quot; \
      --certificate-identity &amp;quot;$CI_PROJECT_URL//.gitlab-ci.yml@refs/heads/$CI_COMMIT_REF_NAME&amp;quot; \
      --certificate-oidc-issuer &amp;quot;$CI_SERVER_URL&amp;quot; | jq.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;What about other CI/CD platforms like Jenkins?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Jenkins, known for being super flexible and having tons of plugins, is still a popular choice, especially for complicated workflows and working with older systems.&lt;/p&gt;
&lt;p&gt;For Jenkins, you&amp;#39;ll need to install the Cosign program on your Jenkins agent(s). This could mean adding commands to your Jenkinsfile or setting up your agents with Cosign already there. If you&amp;#39;re doing key-based signing, Jenkins can safely keep private keys and passwords as credentials. You then just refer to these secrets in your pipeline script.&lt;/p&gt;
&lt;p&gt;While Jenkins doesn&amp;#39;t have the same built-in OIDC support for keyless signing that GitHub or GitLab do, you can still make it work with some more advanced setup. This usually means configuring Jenkins to get OIDC tokens from a supported provider and then giving those tokens to Cosign using the &lt;code&gt;SIGSTORE_ID_TOKEN&lt;/code&gt; environment variable. You might need some custom scripts or special plugins for this.&lt;/p&gt;
&lt;p&gt;Automating image signing inside your &lt;strong&gt;CI/CD&lt;/strong&gt; pipeline turns it into a really important checkpoint for software supply chain security. By putting signing in early in your development process, organizations make sure security isn&amp;#39;t just something you think about later. It&amp;#39;s a core part of building and &lt;strong&gt;deploying&lt;/strong&gt; your software. This automation cuts down on human mistakes, speeds up how fast you can release things, and constantly assures you that every container image you deploy has a verifiable origin and is intact. Your CI/CD pipeline becomes the guardian, automatically applying and checking signatures. That&amp;#39;s crucial for maintaining a strong and trustworthy software supply chain at scale.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Advanced Use Cases: Beyond Basic Signing&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While just signing and checking images is super important, Cosign can do even more. It lets you set up more advanced security, especially in &lt;strong&gt;Kubernetes&lt;/strong&gt; environments.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How do I enforce policies in Kubernetes to ensure only trusted images deploy?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Once your container images are signed, the next smart move is to set up rules that make sure only those signed, trusted images get deployed into your &lt;strong&gt;Kubernetes&lt;/strong&gt; cluster. You do this with admission controllers, which are like &amp;quot;gatekeepers&amp;quot; that catch requests to the Kubernetes API server before anything actually gets saved.&lt;/p&gt;
&lt;p&gt;Popular tools for setting up rules in Kubernetes are Kyverno and Open Policy Agent (OPA) with Gatekeeper. You can set these up to check &lt;strong&gt;Cosign&lt;/strong&gt; signatures before letting new container images into your cluster.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kyverno:&lt;/strong&gt; Kyverno is a policy engine built specifically for Kubernetes. It lets you define policies using YAML, which feels natural if you&amp;#39;re already working with Kubernetes. It can enforce rules that say all container images deployed to a cluster must be signed. A Kyverno &lt;code&gt;ClusterPolicy&lt;/code&gt; can list the image references to check and include the Cosign public key to validate the signature. If an image doesn&amp;#39;t have a valid signature, Kyverno can stop its &lt;strong&gt;deployment&lt;/strong&gt;.
Here is a simplified Kyverno policy example to enforce Cosign signature &lt;strong&gt;verification&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: check-signed-images
spec:
  validationFailureAction: Enforce # Blocks deployment if policy fails
  background: false
  rules:
    - name: require-image-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - &amp;#39;your-registry.com/your-image:*&amp;#39; # Apply to specific images
          attestors:
            - keys:
                publicKeys: |-
                  -----BEGIN PUBLIC KEY-----
                  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE... # Your Cosign public key (cosign.pub content)
                  -----END PUBLIC KEY-----
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you apply this &lt;code&gt;ClusterPolicy&lt;/code&gt; with &lt;code&gt;kubectl apply -f policy.yaml&lt;/code&gt;, it&amp;#39;ll make sure any Pod trying to use an unsigned image (or one signed with a different key) gets blocked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OPA/Gatekeeper:&lt;/strong&gt; OPA Gatekeeper uses Rego, a special language for policies, to define the rules that admission controllers enforce. It can work with Cosign using its ExternalData feature to figure out if images are valid by checking their signatures.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Admission controllers like Kyverno and OPA/Gatekeeper are a really important last line of defense in your software supply chain. They make sure that even if an unsigned or messed-with image somehow gets into&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Container Image Signing: A Practical Guide - Aqua Security, accessed on June 6, 2025, &lt;a href=&quot;https://www.aquasec.com/cloud-native-academy/supply-chain-security/container-image-signing/&quot;&gt;https://www.aquasec.com/cloud-native-academy/supply-chain-security/container-image-signing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sign Container Images with Notation and Azure Key Vault - Learn Microsoft, accessed on June 6, 2025, &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tutorial-sign-build-push&quot;&gt;https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tutorial-sign-build-push&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Use Sigstore for keyless signing and verification - GitLab Docs, accessed on June 6, 2025, &lt;a href=&quot;https://docs.gitlab.com/ci/yaml/signing_examples/&quot;&gt;https://docs.gitlab.com/ci/yaml/signing_examples/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Supply Chain Security: Sigstore and Cosign (Part II) - GitGuardian Blog, accessed on June 6, 2025, &lt;a href=&quot;https://blog.gitguardian.com/supply-chain-security-sigstore-and-cosign-part-ii/&quot;&gt;https://blog.gitguardian.com/supply-chain-security-sigstore-and-cosign-part-ii/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Frequently asked questions - Sigstore, accessed on June 6, 2025, &lt;a href=&quot;https://docs.sigstore.dev/about/faq/&quot;&gt;https://docs.sigstore.dev/about/faq/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Installation - Sigstore, accessed on June 6, 2025, &lt;a href=&quot;https://docs.sigstore.dev/cosign/system_config/installation/&quot;&gt;https://docs.sigstore.dev/cosign/system_config/installation/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Overview - Sigstore, accessed on June 6, 2025, &lt;a href=&quot;https://docs.sigstore.dev/cosign/signing/overview/&quot;&gt;https://docs.sigstore.dev/cosign/signing/overview/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Signing Blobs - Sigstore, accessed on June 6, 2025, &lt;a href=&quot;https://docs.sigstore.dev/cosign/signing/signing_with_blobs/&quot;&gt;https://docs.sigstore.dev/cosign/signing/signing_with_blobs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SBOM attestation - Trivy, accessed on June 6, 2025, &lt;a href=&quot;http://trivy.dev/v0.33/docs/attestation/sbom/&quot;&gt;http://trivy.dev/v0.33/docs/attestation/sbom/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;In-Toto Attestations - Sigstore, accessed on June 6, 2025, &lt;a href=&quot;https://docs.sigstore.dev/cosign/verifying/attestation/&quot;&gt;https://docs.sigstore.dev/cosign/verifying/attestation/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Specifications - Sigstore, accessed on June 6, 2025, &lt;a href=&quot;https://docs.sigstore.dev/cosign/system_config/specifications/&quot;&gt;https://docs.sigstore.dev/cosign/system_config/specifications/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Verify Images | Kyverno, accessed on June 6, 2025, &lt;a href=&quot;https://release-1-9-0.kyverno.io/docs/writing-policies/verify-images/&quot;&gt;https://release-1-9-0.kyverno.io/docs/writing-policies/verify-images/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Image Signing and Attestation with Trivy, Kyverno, and Cosign - Anais Urlichs, accessed on June 6, 2025, &lt;a href=&quot;https://anaisurl.com/trivy-cosign-kyverno/&quot;&gt;https://anaisurl.com/trivy-cosign-kyverno/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Security</category><category>Supply Chain Security</category><category>Containers</category><category>DevSecOps</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0091-container-image-signing-cosign-guide/hero.jpg" length="0" type="image/jpeg"/></item><item><title>GraphRAG Explained: Building Knowledge-Grounded LLM Systems</title><link>https://mkabumattar.com/blog/post/graphrag-explained-building-knowledge-grounded-llm-systems/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/graphrag-explained-building-knowledge-grounded-llm-systems/</guid><description>Think of GraphRAG as the &quot;detective&quot; upgrade for AI. Learn how using Knowledge Graphs helps LLMs connect distant dots, stop hallucinations, and reason through complex data in ways standard RAG just can&apos;t.
</description><pubDate>Sun, 11 Jan 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The world of artificial intelligence is moving fast. We&amp;#39;ve gone from being amazed that Large Language Models can write a poem to wanting them to be deeply grounded in factual truth. While these models are great at generating fluent text, they often struggle with keeping facts straight or reasoning through complex, interconnected data.&lt;/p&gt;
&lt;p&gt;This struggle led to the rise of retrieval-augmented generation (RAG) as the go-to way to give models extra context. But as we&amp;#39;ve asked for more accuracy and deeper thinking, the standard way of using a simple Vector Database has shown some big gaps. To put it simply, standard methods often fail to &amp;quot;connect the dots&amp;quot; when info is scattered across different documents or requires following a logical chain of events. That&amp;#39;s why people are getting excited about GraphRAG. It combines the power of Knowledge Graphs with Large Language Models to create a reasoning engine that&amp;#39;s much more robust, easy to explain, and frankly, just smarter.&lt;/p&gt;
&lt;h2&gt;What exactly is GraphRAG and why is it changing how we use Large Language Models?&lt;/h2&gt;
&lt;p&gt;Think of GraphRAG as a smarter version of the typical AI search systems we use today. At its heart, this technique brings graph-structured data, like knowledge graphs, into the generation process. Unlike traditional systems that treat information like a big pile of isolated text scraps, GraphRAG sees data as a web of connected entities and relationships. This lets the system handle tough questions by using the relational structure of graphs, which organizes info into a network of Nodes and Edges.&lt;/p&gt;
&lt;p&gt;The main reason people are using this is to ground Large Language Models in real facts. This helps stop Hallucinations, which is what happens when a model just makes things up. By giving the AI an explicit map of knowledge, GraphRAG makes sure the model isn&amp;#39;t just guessing the next word based on math probabilities. Instead, it&amp;#39;s actually reasoning over a foundation of Structured Data. This is huge for businesses where an incorrect answer could lead to big financial or legal trouble.&lt;/p&gt;
&lt;p&gt;Microsoft Research really kicked things off with Project GraphRAG. They showed that if you combine text extraction, network analysis, and smart prompting, you can get a much deeper understanding of large datasets than ever before. This isn&amp;#39;t just a small tweak; it’s a total shift in how we model the world for AI. By using graph databases, the system can handle very specific questions that need deep context, like tracking a long chain of events or understanding how a complex company is organized.&lt;/p&gt;
&lt;h2&gt;Why do standard vector-based systems fail when they try to connect distant dots?&lt;/h2&gt;
&lt;p&gt;To see why GraphRAG is so valuable, you have to look at what&amp;#39;s wrong with standard vector-based RAG. Most of these systems rely on Semantic Search using a Vector Database. They cut documents into small chunks, turn them into numbers (embeddings), and find them based on how similar they are to a user’s question. While this works for finding a specific paragraph that looks like the question, it&amp;#39;s &amp;quot;stateless.&amp;quot; It doesn&amp;#39;t understand how different pieces of info relate to each other over time or across different sources.&lt;/p&gt;
&lt;p&gt;One big issue is what people call &amp;quot;crude chunking.&amp;quot; Because models can only look at so much at once, data is often chopped into tiny pieces of 100 to 200 characters. This often breaks the link between a pronoun like &amp;quot;they&amp;quot; and its subject, which might be in a completely different chunk. So, when the system pulls a chunk, it might not even know who or what it&amp;#39;s talking about. Plus, vector similarity measures how &amp;quot;close&amp;quot; words are, but not their logical link. For example, a search for a person in a specific city might fail if one chunk talks about the person and another talks about the city, but no single chunk mentions both.&lt;/p&gt;
&lt;p&gt;Standard systems also hit a wall with &amp;quot;multi-hop reasoning.&amp;quot; This is just a fancy way of saying &amp;quot;following a trail of facts.&amp;quot; If a user asks a question that needs you to connect Fact A in one document to Fact B in another, a vector search will probably find the most similar chunks for each part but won&amp;#39;t be able to bridge the gap. This is where the generator often hallucinates a connection that isn&amp;#39;t there, or just misses the answer because the info was too spread out. Here’s a quick look at those gaps:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Limitation&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Impact on Standard RAG&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Resulting Problem&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Semantic Gaps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pulls info based on topic, not logic.&lt;/td&gt;
&lt;td&gt;You get &amp;quot;near-miss&amp;quot; answers that sound okay but miss the point.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lost Context&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Chunking breaks links between subjects and actions.&lt;/td&gt;
&lt;td&gt;The model gets confused about who did what.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;No Relationship Links&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can&amp;#39;t follow links across different chunks.&lt;/td&gt;
&lt;td&gt;Fails to answer &amp;quot;how is X related to Y&amp;quot; across documents.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stateless Queries&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Treats every question as a new, isolated event.&lt;/td&gt;
&lt;td&gt;Can&amp;#39;t handle follow-up questions or complex reasoning.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Noise Sensitivity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Irrelevant chunks with similar words can hide the truth.&lt;/td&gt;
&lt;td&gt;More hallucinations because the model is trying to make sense of noise.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;How does the structure of Nodes and Edges create a more intelligent map of information?&lt;/h2&gt;
&lt;p&gt;GraphRAG fixes these issues by modeling data the same way our brains do: as a network. In a graph database, info is stored using nodes, edges, and properties. Nodes are the entities like people, companies, or ideas. Edges are the relationships between them, like &amp;quot;works for&amp;quot; or &amp;quot;located in.&amp;quot;&lt;/p&gt;
&lt;p&gt;This makes relationships &amp;quot;first-class citizens.&amp;quot; Instead of trying to guess a relationship when you ask a question, the relationship is already physically there in the database. This lets the system do &amp;quot;multi-hop reasoning&amp;quot; by just following the lines between points on a map. For example, if you need to find the father of a teacher, the system finds the &amp;quot;Teacher&amp;quot; node, follows the &amp;quot;is student of&amp;quot; line to the &amp;quot;Person&amp;quot; node, and then follows the &amp;quot;is child of&amp;quot; line to find the &amp;quot;Father&amp;quot; node.&lt;/p&gt;
&lt;p&gt;By using this structured approach, GraphRAG gives the AI a &amp;quot;grounded context.&amp;quot; Instead of giving the model a bunch of random text snippets, you give it a specific map of entities and their neighbors. This gives the AI a factual chain to follow, so the answer is based on hard facts rather than guesses. This also makes it much easier to explain. You can actually see the path the system took to find the answer.&lt;/p&gt;
&lt;h2&gt;What is the step-by-step technical process for building a knowledge-grounded system?&lt;/h2&gt;
&lt;p&gt;Building a GraphRAG system is a bit of a journey. You start with messy, unstructured text and turn it into a clean, queryable network. Usually, you&amp;#39;ll use frameworks like LangChain and graph databases like Neo4j to handle the heavy lifting.&lt;/p&gt;
&lt;h3&gt;Step 1: Extracting Knowledge and Finding Entities&lt;/h3&gt;
&lt;p&gt;The first goal is to turn raw docs like emails or reports into nodes and edges. You use a Large Language Model to act as your &amp;quot;analyst.&amp;quot; The system identifies key people and places (NER) and then figures out how they&amp;#39;re linked. For example, the sentence &amp;quot;Neo4j is used by OpenAI&amp;quot; becomes a triplet: (OpenAI) --&amp;gt; (Neo4j).&lt;/p&gt;
&lt;p&gt;You can see how this works in code using LangChain&amp;#39;s graph transformers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Here we take raw text and turn it into graph documents
# This identifies the &amp;quot;nodes&amp;quot; and &amp;quot;relationships&amp;quot; for us
from langchain_experimental.graph_transformers import LLMGraphTransformer
from langchain_openai import ChatOpenAI

# Initialize the model that will do the heavy lifting
llm = ChatOpenAI(model=&amp;quot;gpt-4o&amp;quot;, temperature=0)
transformer = LLMGraphTransformer(llm=llm)

# Convert your documents into a graph structure
# This is where the magic of entity extraction happens
graph_documents = transformer.convert_to_graph_documents(my_raw_documents)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Storing the Knowledge Graph&lt;/h3&gt;
&lt;p&gt;Once you&amp;#39;ve got your entities, you save them in a graph database. This usually involves using a query language like Cypher to create the nodes while making sure you don&amp;#39;t create duplicates. You&amp;#39;ll often use an &amp;quot;ontology,&amp;quot; which is just a fancy word for a map that tells the system what types of things to look for.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Connecting to your Neo4j database to store the new graph
from langchain_community.graphs import Neo4jGraph

graph = Neo4jGraph(
    url=&amp;quot;bolt://localhost:7687&amp;quot;,
    username=&amp;quot;neo4j&amp;quot;,
    password=&amp;quot;your_password&amp;quot;
)

# Adding the documents we just transformed into the database
graph.add_graph_documents(graph_documents)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Community Detection and Summarization&lt;/h3&gt;
&lt;p&gt;This is where it gets really cool. You can use algorithms like &amp;quot;Leiden&amp;quot; to find clusters of nodes that are closely linked. These clusters represent themes that emerged from your data. The system then summarizes these communities at different levels. This creates a multi-layered map, so the system can answer big-picture questions just as easily as specific ones.&lt;/p&gt;
&lt;h3&gt;Step 4: Running Queries and Grabbing Subgraphs&lt;/h3&gt;
&lt;p&gt;When you ask a question, the system doesn&amp;#39;t just look for similar words. It maps your question to the entities in the graph. Then it pulls a &amp;quot;relevant neighborhood&amp;quot; of info, usually looking a few &amp;quot;hops&amp;quot; away from the main entities to get all the context it needs.&lt;/p&gt;
&lt;h3&gt;Step 5: Generating the Answer&lt;/h3&gt;
&lt;p&gt;Finally, you give the pulled graph data and the question to the AI. You tell it to answer using &lt;em&gt;only&lt;/em&gt; the facts from the graph. Because the context is clean and validated, the answers are much more detailed and accurate than a standard search.&lt;/p&gt;
&lt;h2&gt;How does the retrieval process work when navigating a complex web of relationships?&lt;/h2&gt;
&lt;p&gt;Finding info in a GraphRAG system is much more active than just looking something up in a database. It uses both semantic meaning and the actual structure of the graph. A standard vector search is like a librarian looking for a book, but a GraphRAG search is like a detective following a trail.&lt;/p&gt;
&lt;p&gt;One way to search is &amp;quot;local search,&amp;quot; which looks at nodes directly linked to your question. If you ask &amp;quot;Who made the theory of relativity?&amp;quot;, the system finds that node and follows the &amp;quot;made by&amp;quot; line to &amp;quot;Albert Einstein.&amp;quot;&lt;/p&gt;
&lt;p&gt;There&amp;#39;s also &amp;quot;global search,&amp;quot; which is great for big questions that cover the whole dataset. Instead of looking at individual points, it looks at the summaries of those &amp;quot;communities&amp;quot; we talked about earlier. This lets it answer things like &amp;quot;What are the main political trends in these reports?&amp;quot; by bringing together insights from different clusters.&lt;/p&gt;
&lt;p&gt;To get the best results, many systems use a &amp;quot;hybrid approach.&amp;quot; They use semantic search to find a starting point and then use graph traversal to find the logical links that a simple word search would miss.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Search Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;How it Works&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;When to Use It&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Local Search&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Looks at direct links around a specific entity.&lt;/td&gt;
&lt;td&gt;Specific questions about a person, place, or thing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Global Search&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Uses summaries of themed clusters.&lt;/td&gt;
&lt;td&gt;Big-picture summaries and &amp;quot;top themes&amp;quot; questions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hybrid Search&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Combines word similarity with graph paths.&lt;/td&gt;
&lt;td&gt;Questions that use both vague language and specific terms.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DRIFT Search&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dynamically moves through the graph based on the query.&lt;/td&gt;
&lt;td&gt;Tough queries that need different levels of depth.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-Hop Search&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Traces paths through several nodes (A to B to C).&lt;/td&gt;
&lt;td&gt;Uncovering hidden links between distant facts.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;In what ways does GraphRAG help stop hallucinations and make answers more accurate?&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve all seen AI just &amp;quot;fill in the blanks&amp;quot; when it doesn&amp;#39;t know the answer. Since models are trained to predict the next word, they&amp;#39;ll often give you a fake answer that sounds perfectly real if they don&amp;#39;t have enough context. GraphRAG stops this by creating a &amp;quot;grounded&amp;quot; environment where the model has to stick to explicit facts.&lt;/p&gt;
&lt;p&gt;By using a knowledge graph, the system can show you exactly where an answer came from this is called &amp;quot;provenance.&amp;quot; It can point to the specific node or link in the graph, and even back to the original document. This makes the AI much more trustworthy, especially in fields like medicine or finance where you can&amp;#39;t afford to guess.&lt;/p&gt;
&lt;p&gt;It also helps by keeping the context &amp;quot;compact.&amp;quot; Traditional RAG might bury the AI in irrelevant text, making it miss the &amp;quot;needle in the haystack.&amp;quot; GraphRAG cleans up the data before the AI sees it, removing the noise and leaving only the important context. This lets the AI think more clearly and give answers that are logically sound.&lt;/p&gt;
&lt;h2&gt;RAG vs GraphRAG: What are the big differences in how they perform and what they cost?&lt;/h2&gt;
&lt;p&gt;When choosing between these two, you have to balance accuracy against cost and effort. GraphRAG is much more powerful for tough tasks, but it&amp;#39;s also more work to build.&lt;/p&gt;
&lt;p&gt;Traditional RAG is like a librarian who’s fast and cheap to hire. It’s easy to set up, handles unstructured text well, and gives fast answers because vector search is a very mature tech. But its accuracy on complex, &amp;quot;multi-hop&amp;quot; questions is often below 60%.&lt;/p&gt;
&lt;p&gt;GraphRAG is more like a master detective. It&amp;#39;s more expensive to set up because you need a powerful AI to extract all those entities and relationships upfront. That process can be slow. But once it&amp;#39;s built, it can be way more accurate sometimes by as much as 35% on complex tasks. It also uses fewer &amp;quot;tokens&amp;quot; when generating an answer because it gives the AI only the most relevant, summarized data, which can save money in the long run.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Metric&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Vector RAG&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;GraphRAG&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fast (Just index the text).&lt;/td&gt;
&lt;td&gt;Slower (Needs extraction).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Response Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very fast similarity search.&lt;/td&gt;
&lt;td&gt;Moderate (Traversal takes time).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Accuracy (Complex)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Often misses the link.&lt;/td&gt;
&lt;td&gt;Very good at connecting dots.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Explainability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low (Black-box math).&lt;/td&gt;
&lt;td&gt;High (You can trace the path).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate (Vector index).&lt;/td&gt;
&lt;td&gt;Higher (Graph DB needed).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maintenance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low (Add new chunks).&lt;/td&gt;
&lt;td&gt;Higher (Update the web of links).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;How is GraphRAG changing fields like medicine, law, and finance?&lt;/h2&gt;
&lt;p&gt;You can see the real power of GraphRAG in industries where a wrong answer is a disaster. In these areas, being able to reason through connections is a must-have.&lt;/p&gt;
&lt;h3&gt;Better Medical Diagnostics&lt;/h3&gt;
&lt;p&gt;In healthcare, a patient might have symptoms that look like several different things. A system like MedRAG uses a medical knowledge graph to link symptoms, diseases, and treatments. By thinking through these links, it can lower misdiagnosis rates and even ask the right follow-up questions to get more info. One hospital found that their GraphRAG assistant cut diagnostic errors by 30%.&lt;/p&gt;
&lt;h3&gt;Stopping Financial Fraud&lt;/h3&gt;
&lt;p&gt;Criminals often hide their tracks by moving money through a maze of different accounts. Vector systems often miss these &amp;quot;long-distance&amp;quot; links because they only look for similar patterns in text. GraphRAG can trace money across thousands of nodes and edges to find suspicious webs. It&amp;#39;s been shown to find twice as many suspicious patterns as older methods.&lt;/p&gt;
&lt;h3&gt;Improving Legal Research&lt;/h3&gt;
&lt;p&gt;Legal work is all about navigating a massive hierarchy of laws and court cases. A lawyer needs to know not just what a law says, but how it’s been used in court. GraphRAG lets legal researchers navigate these links directly, making their work much more accurate and saving a ton of time on manual review. It keeps the AI grounded in actual legal facts, which is vital for trust in the courtroom.&lt;/p&gt;
&lt;h2&gt;What are the technical barriers to making these systems scale?&lt;/h2&gt;
&lt;p&gt;Even though it&amp;#39;s powerful, GraphRAG isn&amp;#39;t perfect. Setting it up for a big company comes with some real hurdles.&lt;/p&gt;
&lt;p&gt;The biggest one is just building the graph. Extracting correct entities from millions of docs needs a very solid pipeline and expensive AI models. If the extraction is messy the &amp;quot;garbage in, garbage out&amp;quot; problem the graph won&amp;#39;t be accurate, and the AI will make bad calls. This is even harder when dealing with industry jargon or words that have multiple meanings.&lt;/p&gt;
&lt;p&gt;Scaling is also a concern. As the graph grows to millions of nodes, moving through it can get slow. There&amp;#39;s also &amp;quot;neighborhood explosion,&amp;quot; which is what happens when one node is linked to too many other things, making it hard for the system to pick the right path.&lt;/p&gt;
&lt;p&gt;Finally, you have the &amp;quot;entity resolution&amp;quot; headache. The system has to know that &amp;quot;IBM&amp;quot; and &amp;quot;International Business Machines&amp;quot; are the same thing. If it thinks they&amp;#39;re different, the links in your graph will be broken. While AI is getting better at this, it still needs constant checking by humans.&lt;/p&gt;
&lt;h2&gt;What’s next for the future of GraphRAG?&lt;/h2&gt;
&lt;p&gt;The future is all about making these systems faster, cheaper, and more adaptive. Researchers are finding ways to build graphs without needing expensive, high-end models for every single step.&lt;/p&gt;
&lt;p&gt;We’re also seeing the rise of &amp;quot;agentic&amp;quot; retrievers. These are AI agents that can actually plan a multi-step search, deciding when to use a simple vector search and when to go deep into a graph traversal. They&amp;#39;ll be able to move fluidly between different types of data to find the best answer possible.&lt;/p&gt;
&lt;p&gt;Lastly, &amp;quot;Multimodal GraphRAG&amp;quot; will let us link more than just text. We&amp;#39;ll be able to connect images, video, and data from sensors into one big knowledge network. Think of a self-driving car linking real-time camera data with traffic laws and maps to make safer choices on the fly. As this tech grows up, the gap between how AI thinks and how we think will keep getting smaller, leading to systems we can really trust.&lt;/p&gt;
&lt;h3&gt;Frequently Asked Questions&lt;/h3&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Is GraphRAG much slower than standard RAG?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;It can be. Because the system has to follow paths through a graph instead of just doing a single mathematical comparison, it usually takes more processing time. However, for complex questions, that extra time is usually worth the much higher accuracy.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can I use GraphRAG with my existing vector database?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes! Most modern systems are actually &amp;quot;hybrid.&amp;quot; They use a vector database to find a good starting point and then use the graph to explore the relationships from there.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Do I need a special database for this?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;You typically need a graph database like Neo4j or FalkorDB. These are built specifically to handle the &amp;quot;nodes and edges&amp;quot; structure efficiently.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do I handle new data without rebuilding the whole graph?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Newer techniques like &amp;quot;LazyGraphRAG&amp;quot; or &amp;quot;on-the-fly&amp;quot; processing allow you to update the graph and add new links without starting from scratch.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What is GraphRAG? - IBM, accessed on December 23, 2025, &lt;a href=&quot;https://www.ibm.com/think/topics/graphrag&quot;&gt;https://www.ibm.com/think/topics/graphrag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Project GraphRAG - Microsoft Research, accessed on December 23, 2025, &lt;a href=&quot;https://www.microsoft.com/en-us/research/project/graphrag/&quot;&gt;https://www.microsoft.com/en-us/research/project/graphrag/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GraphRAG Explained: Building Knowledge-Grounded LLM Systems - Towards AI, accessed on December 23, 2025, &lt;a href=&quot;https://pub.towardsai.net/graphrag-explained-building-knowledge-grounded-llm-systems-with-neo4j-and-langchain-017a1820763e&quot;&gt;https://pub.towardsai.net/graphrag-explained-building-knowledge-grounded-llm-systems-with-neo4j-and-langchain-017a1820763e&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RAG vs Graph RAG: Key Technical Differences - HashStudioz Technologies, accessed on December 23, 2025, &lt;a href=&quot;https://www.hashstudioz.com/blog/difference-between-rag-and-graph-rag-a-technical-perspective/&quot;&gt;https://www.hashstudioz.com/blog/difference-between-rag-and-graph-rag-a-technical-perspective/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Implementing &amp;#39;From Local to Global&amp;#39; GraphRAG With Neo4j and LangChain - Neo4j, accessed on December 23, 2025, &lt;a href=&quot;https://neo4j.com/blog/developer/global-graphrag-neo4j-langchain/&quot;&gt;https://neo4j.com/blog/developer/global-graphrag-neo4j-langchain/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Graph RAG vs RAG: Which One Is Truly Smarter for AI Retrieval? - Data Science Dojo, accessed on December 23, 2025, &lt;a href=&quot;https://datasciencedojo.com/blog/graph-rag-vs-rag/&quot;&gt;https://datasciencedojo.com/blog/graph-rag-vs-rag/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Navigating the Nuances of GraphRAG vs. RAG - Foojay.io, accessed on December 23, 2025, &lt;a href=&quot;https://foojay.io/today/navigating-the-nuances-of-graphrag-vs-rag/&quot;&gt;https://foojay.io/today/navigating-the-nuances-of-graphrag-vs-rag/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The limitations of vector retrieval for enterprise RAG - WRITER, accessed on December 23, 2025, &lt;a href=&quot;https://writer.com/blog/vector-based-retrieval-limitations-rag/&quot;&gt;https://writer.com/blog/vector-based-retrieval-limitations-rag/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Graph RAG vs. Classical RAG: A Comparative Analysis - ELEKS, accessed on December 23, 2025, &lt;a href=&quot;https://eleks.com/research/graph-rag-vs-classical-rag-analysis/&quot;&gt;https://eleks.com/research/graph-rag-vs-classical-rag-analysis/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RAG Tutorial: How to Build a RAG System on a Knowledge Graph - Neo4j, accessed on December 23, 2025, &lt;a href=&quot;https://neo4j.com/blog/developer/rag-tutorial/&quot;&gt;https://neo4j.com/blog/developer/rag-tutorial/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Improve Multi-Hop Reasoning With Knowledge Graphs and LLMs - Neo4j, accessed on December 23, 2025, &lt;a href=&quot;https://neo4j.com/blog/genai/knowledge-graph-llm-multi-hop-reasoning/&quot;&gt;https://neo4j.com/blog/genai/knowledge-graph-llm-multi-hop-reasoning/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is GraphRAG? Different Types, Limitations, and When to Use - FalkorDB, accessed on December 23, 2025, &lt;a href=&quot;https://www.falkordb.com/blog/what-is-graphrag/&quot;&gt;https://www.falkordb.com/blog/what-is-graphrag/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GraphRAG: Unlocking LLM discovery on narrative private data - Microsoft Research, accessed on December 23, 2025, &lt;a href=&quot;https://www.microsoft.com/en-us/research/blog/graphrag-unlocking-llm-discovery-on-narrative-private-data/&quot;&gt;https://www.microsoft.com/en-us/research/blog/graphrag-unlocking-llm-discovery-on-narrative-private-data/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Boosting Q&amp;amp;A Accuracy with GraphRAG Using PyG and Graph Databases - NVIDIA, accessed on December 23, 2025, &lt;a href=&quot;https://developer.nvidia.com/blog/boosting-qa-accuracy-with-graphrag-using-pyg-and-graph-databases/&quot;&gt;https://developer.nvidia.com/blog/boosting-qa-accuracy-with-graphrag-using-pyg-and-graph-databases/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MedRAG: Enhancing Retrieval-augmented Generation with Knowledge Graph-Elicited Reasoning - arXiv, accessed on December 23, 2025, &lt;a href=&quot;https://arxiv.org/html/2502.04413v1&quot;&gt;https://arxiv.org/html/2502.04413v1&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Artificial Intelligence</category><category>Machine Learning</category><category>Large Language Models</category><category>Knowledge Graphs</category><category>RAG Systems</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0090-graphrag-explained-building-knowledge-grounded-llm-systems/hero.jpg" length="0" type="image/jpeg"/></item><item><title>The Resilience of Timbernetes: A Comprehensive Analysis of In-Place Pod Vertical Scaling in Kubernetes 1.35</title><link>https://mkabumattar.com/blog/post/kubernetes-1-35-in-place-pod-vertical-scaling-guide/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/kubernetes-1-35-in-place-pod-vertical-scaling-guide/</guid><description>Discover how Kubernetes 1.35 &quot;Timbernetes&quot; revolutionizes resource management with In-Place Pod Vertical Scaling. This expert report explores the shift from &quot;restart-to-scale&quot; to a dynamic update model, focusing on benefits for JVM and stateful services. Learn how the kubelet, VPA, and cgroups v2 work together to enable zero-downtime scaling, improve node utilization, and manage memory shrink hazards. Essential reading for DevOps and platform engineers looking to optimize Kubernetes workloads.
</description><pubDate>Sun, 04 Jan 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The release of Kubernetes 1.35, officially designated as &amp;quot;Timbernetes,&amp;quot; represents a definitive shift in the architectural philosophy of cloud-native orchestration. This version marks the graduation of In-Place Pod Vertical Scaling (KEP-1287) to General Availability (GA), a transition that fundamentally alters the lifecycle management of containerized workloads. For more than six years, the Kubernetes community has grappled with the limitations of an immutable resource model where changing the compute power of a running pod necessitated its destruction and recreation. The &amp;quot;restart-to-scale&amp;quot; paradigm, while consistent with early microservices doctrine, imposed a significant operational burden on complex, stateful, and latency-sensitive applications. By making container resources mutable within the pod spec, Kubernetes 1.35 empowers the kubelet to adjust resource limits on the fly, directly modifying the underlying kernel control groups (cgroups) without signaling a process restart. This advancement is particularly transformative for high-stakes environments, such as those hosting Java Virtual Machine (JVM) applications or large-scale stateful sets, where the &amp;quot;restart tax&amp;quot; was previously measured in performance degradation, lost cache states, and service downtime.&lt;/p&gt;
&lt;h2&gt;Why is the Graduation of In-Place Pod Scaling the Definitive Feature of the Kubernetes 1.35 Release?&lt;/h2&gt;
&lt;p&gt;The maturation of In-Place Pod Vertical Scaling into a stable feature in Kubernetes 1.35 is not merely an incremental update; it is the resolution of a foundational friction point in the platform&amp;#39;s history. Since its inception as an alpha feature in version 1.27, this capability has been designed to address the inefficiency of static resource allocation. In the traditional model, developers were forced into a binary choice: overprovision resources to ensure peak performance, leading to wasted node utilization, or underprovision and risk pod evictions or Out-Of-Memory (OOM) failures during traffic surges. The 1.35 release solves this by allowing the Vertical Pod Autoscaler (VPA) and other controllers to tune container resources dynamically.&lt;/p&gt;
&lt;p&gt;The symbolism of the &amp;quot;Timbernetes&amp;quot; name, as noted by the release team, reflects a project that is growing deep roots and expanding its branches to support the most demanding modern workloads, including artificial intelligence (AI) training and edge computing. These workloads often exhibit volatile resource requirements that do not align well with the overhead of pod recreation. In-place scaling allows a pod to expand its resource envelope as a training job intensifies or as a game server experiences a sudden influx of players, ensuring that the infrastructure responds at the speed of the application rather than the speed of the orchestration layer.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Legacy &amp;quot;Restart-to-Scale&amp;quot; Model&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Kubernetes 1.35 Dynamic Update Model&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pod Specification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Immutable resource fields for CPU and memory.&lt;/td&gt;
&lt;td&gt;Mutable resource requests and limits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operational Impact&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pod recreation required; IP address and UID changes.&lt;/td&gt;
&lt;td&gt;Pod remains running; identity and network remain intact.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling Velocity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited by image pull time and startup probes.&lt;/td&gt;
&lt;td&gt;Immediate cgroup modification via the kubelet.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Retention&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;In-memory caches and JIT optimizations are lost.&lt;/td&gt;
&lt;td&gt;Full retention of in-memory state and optimized code.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Risk Profile&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High; new pod may fail to schedule on the node.&lt;/td&gt;
&lt;td&gt;Low; scaling is performed on the already admitted node.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;How Does the Shift from Restart-to-Scale to Dynamic Updates Change Pod Lifecycle Management?&lt;/h2&gt;
&lt;p&gt;The transition to a dynamic update model fundamentally redefines the relationship between the pod spec and the running container. Historically, the &lt;code&gt;resources&lt;/code&gt; field within a pod’s container definition was considered a fixed contract established at the moment of scheduling. Under the new model in Kubernetes 1.35, the &lt;code&gt;spec.containers[*].resources&lt;/code&gt; field represents a &amp;quot;desired state&amp;quot; that can be modified via the new &lt;code&gt;resize&lt;/code&gt; subresource. This subresource allows for specialized permissions, ensuring that only authorized entities like the VPA or a cluster administrator can trigger a vertical scale event.&lt;/p&gt;
&lt;p&gt;When an update is initiated, the kubelet on the node takes responsibility for reconciling the desired state with the actual hardware allocation. This process is asynchronous, meaning the API server accepts the change and then waits for the kubelet to report back whether the resize was successful, deferred, or infeasible. The use of cgroups v2 is a prerequisite for this functionality, as it provides the unified hierarchy and improved resource isolation necessary for reliable on-the-fly adjustments. Kubernetes 1.35 draws a hard line here, deprecating cgroup v1 support to ensure that the platform can fully leverage these modern kernel features.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Resource Field&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Role in Kubernetes 1.35&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Visibility/Location&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Desired Resources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The user-requested CPU and memory values.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;spec.containers[*].resources&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Admitted Resources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Resources the node has committed to the pod.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;status.containerStatuses[*].allocatedResources&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configured Resources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The values currently enforced by the container runtime.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;status.containerStatuses[*].resources&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;This three-way tracking ensures that the control plane always understands the gap between what is requested and what is currently running. If a node lacks the capacity to fulfill a resize request, the kubelet marks the status as &lt;code&gt;PodResizePending&lt;/code&gt; or &lt;code&gt;Infeasible&lt;/code&gt;, preventing the cluster from over-committing resources while keeping the original pod running at its current capacity.&lt;/p&gt;
&lt;h2&gt;What are the Practical Benefits of In-Place Scaling for JVM Applications and High-Stakes Services?&lt;/h2&gt;
&lt;p&gt;Java Virtual Machine (JVM) applications are among the primary beneficiaries of in-place scaling due to their sensitivity to restarts. When a JVM restarts, it loses its Just-In-Time (JIT) compilation optimizations. The JIT compiler is responsible for analyzing execution patterns and translating frequently used bytecode into highly optimized machine code. A restart forces the JVM back to an interpreted state, causing a &amp;quot;cold start&amp;quot; where the application consumes significantly more CPU to re-warm its cache. In high-traffic environments, these cold starts can trigger a cascade of failures as the unoptimized application struggles to meet its latency Service Level Agreements (SLAs).&lt;/p&gt;
&lt;p&gt;Furthermore, many Java applications require significant memory for their heap space. In a traditional Kubernetes environment, if the VPA recommended a memory increase, the resulting restart would kill active transactions and sever database connections. With Kubernetes 1.35, the pod can increase its memory limit in place. While the JVM may still require specific flags to recognize and use the newly available memory without a restart, the infrastructure no longer forces a hard termination.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Application Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Restart Penalty&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;In-Place Scaling Advantage&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JVM (Java/Kotlin)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Loss of JIT optimizations; high startup CPU spike.&lt;/td&gt;
&lt;td&gt;Maintains optimized machine code; smooth CPU scaling.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PostgreSQL / MySQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WAL replay; termination of active queries.&lt;/td&gt;
&lt;td&gt;Continuous query processing during memory expansion.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redis / Memcached&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cache flush; immediate hit to backend databases.&lt;/td&gt;
&lt;td&gt;Caches remain hot; no backend storm upon scaling.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI / ML Training&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Loss of training epoch progress; GPU re-initialization.&lt;/td&gt;
&lt;td&gt;Continuous training; dynamic resource adjustment per phase.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;For stateful sets, such as databases and distributed caches, the benefits are equally profound. These services often maintain large in-memory data structures. Restarting a database instance often requires replaying logs or re-populating caches, a process that can take minutes for large datasets. In-place scaling allows these services to expand their resource requests as load grows, ensuring that the application remains responsive without the risk of data inconsistency or connection storms during a rolling restart.&lt;/p&gt;
&lt;h2&gt;How does the Kubelet Manage Resource Limits and Node Utilization during an In-Place Resize?&lt;/h2&gt;
&lt;p&gt;The kubelet acts as the ultimate authority on whether a resize can occur on a given node. When the desired resource update reaches the node, the kubelet calculates the remaining unallocated capacity. This calculation accounts for the &lt;code&gt;pod.spec.resources&lt;/code&gt; of all other pods currently running on the node. If the node has sufficient space, the kubelet issues a call to the container runtime (containerd or CRI-O) to update the cgroup settings.&lt;/p&gt;
&lt;p&gt;A key innovation in the 1.35 release is the &amp;quot;Memory Shrink Hazard&amp;quot; protection. Decreasing a memory limit is inherently risky; if an application&amp;#39;s current usage exceeds the new, lower limit, the kernel will immediately trigger an OOM-kill. To prevent this, the kubelet in 1.35 performs a best-effort check of the current memory usage before applying a decrease. If the usage is too high, the resize enters a &lt;code&gt;PodResizeInProgress&lt;/code&gt; state with an error message, and the limit is not lowered until the application naturally reduces its memory footprint.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Node Utilization Factor&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Role of In-Place Scaling&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bin-Packing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Allows pods to be sized tightly; expands only when needed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resource Reclamation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Idle CPU/memory can be reclaimed without restarting pods.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scheduling Pressure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reduces the number of scheduling events for scaling.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OOM Prevention&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limits can be increased proactively as usage spikes.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;This dynamic management significantly improves node utilization. In traditional clusters, administrators often leave a &amp;quot;buffer&amp;quot; of unused resources on each node to accommodate pod restarts and spikes. With in-place scaling, clusters can run closer to their physical capacity because the system can reallocate resources between running pods as demand shifts. This moves Kubernetes closer to a true &amp;quot;fluid&amp;quot; infrastructure model where hardware is shared optimally in real-time.&lt;/p&gt;
&lt;h2&gt;What is the Role of the Vertical Pod Autoscaler (VPA) in the New 1.35 Resource Landscape?&lt;/h2&gt;
&lt;p&gt;The Vertical Pod Autoscaler has long been the &amp;quot;missing piece&amp;quot; for automated Kubernetes scaling, often overshadowed by the Horizontal Pod Autoscaler (HPA) because of its disruptive nature. In version 1.35, the VPA&amp;#39;s integration with in-place scaling transitions it from a recommendation engine into a primary scaling tool. The new &lt;code&gt;InPlaceOrRecreate&lt;/code&gt; update mode, which graduated to beta in this release, allows the VPA to apply its recommendations with minimal impact.&lt;/p&gt;
&lt;p&gt;When a VPA object is configured with &lt;code&gt;updateMode: InPlaceOrRecreate&lt;/code&gt;, it periodically analyzes the historical resource consumption of its target pods. If it determines that a pod is over-provisioned or under-provisioned, it attempts to patch the running pod. This prevents the &amp;quot;vicious cycle&amp;quot; where a VPA would evict a pod to increase its resources, only for the new pod to fail to schedule because the node was already full.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;VPA Update Mode&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Behavioral Logic&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Disruption Level&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Off&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Recommender calculates values; no action taken.&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Initial&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Recommendations applied only during pod creation.&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Recreate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Evicts pod to apply new resource values.&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;InPlaceOrRecreate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Attempts in-place resize; falls back to eviction if needed.&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;One significant advantage of the 1.35 release is the removal of the blocker for running VPA and HPA simultaneously. Historically, using both could lead to a conflict where one would scale horizontally while the other scaled vertically, causing cluster instability. With in-place scaling, architects can configure VPA to manage the specific resource requests (right-sizing) while HPA manages the number of replicas based on custom metrics or external demand, leading to a more holistic scaling strategy.&lt;/p&gt;
&lt;h2&gt;How do Pod Specification Changes and Resize Policies Ensure Application Stability?&lt;/h2&gt;
&lt;p&gt;The introduction of mutable resources in the pod spec is accompanied by a new field called &lt;code&gt;resizePolicy&lt;/code&gt;. This field allows developers to tell Kubernetes how their specific application handles resource changes. Not every application can utilize extra memory immediately; for example, some legacy databases allocate a buffer pool at startup that cannot be resized without a restart.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;resizePolicy&lt;/code&gt; includes two primary options: &lt;code&gt;NotRequired&lt;/code&gt; and &lt;code&gt;RestartContainer&lt;/code&gt;. By default, CPU is set to &lt;code&gt;NotRequired&lt;/code&gt;, as the Linux kernel can seamlessly grant more cycles to a running process. Memory often defaults to &lt;code&gt;RestartContainer&lt;/code&gt; in many production templates to ensure that the application environment is re-initialized to recognize the new limits. If a pod contains both CPU and memory updates and the memory policy requires a restart, the entire container will restart to ensure consistent state.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Policy Field&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Common Use Case&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NotRequired&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Changes are applied to cgroups; no process signal sent.&lt;/td&gt;
&lt;td&gt;CPU scaling; modern memory-aware apps (e.g., Go).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RestartContainer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Container is terminated and restarted with new limits.&lt;/td&gt;
&lt;td&gt;Legacy Java apps with fixed &lt;code&gt;-Xmx&lt;/code&gt; settings.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Another critical guardrail in Kubernetes 1.35 is the immutability of the Quality of Service (QoS) class. A pod&amp;#39;s QoS class (Guaranteed, Burstable, or BestEffort) is a fundamental attribute used for scheduling and eviction decisions. Allowing a pod to change from &amp;quot;Guaranteed&amp;quot; to &amp;quot;Burstable&amp;quot; during its life would invalidate the scheduler&amp;#39;s initial decision to place it on a specific node. Consequently, if a resize request would result in a QoS class change, the API server will reject the update. This ensures that high-priority workloads maintain their performance guarantees throughout their lifecycle.&lt;/p&gt;
&lt;h2&gt;What Advanced Capabilities Does Kubernetes 1.35 Introduce for Resource Efficiency?&lt;/h2&gt;
&lt;p&gt;While in-place pod scaling is the headline feature, version 1.35 includes several alpha-stage enhancements that point toward the future of resource management. One of the most significant is the introduction of Pod-Level Resource Specifications (KEP-2837). In the current Kubernetes model, resources are defined at the container level, and the pod&amp;#39;s total is merely the sum of its parts. This often leads to &amp;quot;internal waste&amp;quot; in multi-container pods, where a sidecar might be sitting idle while the main application is throttled.&lt;/p&gt;
&lt;p&gt;The new pod-level resource feature allows operators to set an aggregate request and limit for the entire pod. This creates a shared &amp;quot;resource bucket&amp;quot; that all containers in the pod can draw from dynamically. When combined with the alpha &lt;code&gt;InPlacePodLevelResourcesVerticalScaling&lt;/code&gt; feature gate, this allows for the vertical scaling of the entire pod&amp;#39;s bucket without service disruption. This is a major leap forward for complex pods running sidecars for service mesh, logging, or security, as it allows for fluid resource sharing within the pod boundary.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature Name&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Release Status in 1.35&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Primary Benefit&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;In-Place Pod Resize&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;General Availability (GA)&lt;/td&gt;
&lt;td&gt;Production-ready zero-downtime vertical scaling.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pod-Level Resources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Alpha&lt;/td&gt;
&lt;td&gt;Aggregate resource sharing between containers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Native Gang Scheduling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Alpha&lt;/td&gt;
&lt;td&gt;Ensures all pods in a group start together (AI training).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node Declared Features&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Alpha&lt;/td&gt;
&lt;td&gt;Prevents version skew issues during pod scheduling.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Additionally, &amp;quot;Native Gang Scheduling&amp;quot; (KEP-4671) enters alpha, providing a critical tool for AI and High-Performance Computing (HPC) workloads. This feature ensures &amp;quot;all-or-nothing&amp;quot; scheduling, where a group of pods is only admitted to the cluster if resources are available for every member. This prevents scenarios where half of a training job burns expensive GPU cycles while waiting for its peers to be scheduled, a common pain point in distributed machine learning.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Does In-Place Pod Vertical Scaling require a specific container runtime?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, the feature relies on the Container Runtime Interface (CRI) to communicate resource changes to the underlying kernel. Kubernetes 1.35 requires a compatible version of either containerd (v1.6.9 or later) or CRI-O (v1.24.2 or later). These runtimes are designed to receive the update from the kubelet and apply the changes to the container&amp;#39;s cgroups without stopping the process.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What happens if I try to scale a pod beyond the capacity of its current node?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;If a resize request exceeds the available resources on the node where the pod is running, the kubelet will not apply the change. The request will be marked as &lt;code&gt;Infeasible&lt;/code&gt; or &lt;code&gt;PodResizePending&lt;/code&gt; in the pod&amp;#39;s status. The pod will continue to run at its original resource levels. If you are using the VPA in &lt;code&gt;InPlaceOrRecreate&lt;/code&gt; mode, the VPA may eventually decide to evict the pod so it can be rescheduled on a node with more capacity.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can I decrease the memory limit of a running pod safely?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Kubernetes 1.35 introduces a &amp;quot;best-effort&amp;quot; protection for memory shrinks. Before lowering the limit, the kubelet checks the container’s current memory usage. If the usage is higher than the new desired limit, the resize is deferred to prevent an immediate OOM-kill. However, this is not a perfect guarantee; if the application&amp;#39;s memory usage spikes immediately after the check but before the limit is applied, an OOM-kill can still occur.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does In-Place Scaling affect my cluster&amp;#39;s cost-efficiency?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;In-place scaling is a cornerstone of &amp;quot;FinOps&amp;quot; for Kubernetes. By allowing pods to be sized based on their current needs rather than their peak historical usage, it enables tighter bin-packing. This means you can fit more pods onto fewer nodes, reducing the overall cloud provider bill. Furthermore, it allows for the reclamation of idle resources from one pod to give to another on the same node without the churn of restarts.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Is In-Place Pod Scaling enabled by default in Kubernetes 1.35?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, as a GA feature, In-Place Pod Vertical Scaling is enabled by default in version 1.35. However, it requires that your nodes are running on cgroup v2-enabled Linux distributions. If your cluster relies on legacy cgroup v1 nodes, the kubelet will not support this feature and, in some cases, may fail to start in 1.35 without specific configuration.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Does this feature work for pods in a StatefulSet?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Absolutely. In fact, stateful sets are one of the primary targets for this feature. By using in-place scaling, you can vertically scale the members of a StatefulSet (such as a database cluster) one by one without triggering the traditional rolling update that causes temporary loss of availability or leader elections.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can I change other resources, like GPUs or ephemeral storage, in place?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;No. As of Kubernetes 1.35, the In-Place Pod Resize feature is strictly limited to CPU and memory resources. Other resource types, including GPUs managed via Device Plugins or ephemeral storage, remain immutable and still require a pod restart to modify.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The graduation of In-Place Pod Vertical Scaling to General Availability in Kubernetes 1.35 marks a high-water mark for the platform&amp;#39;s operational maturity. By dismantling the &amp;quot;restart-to-scale&amp;quot; barrier, the Kubernetes project has addressed one of the most persistent challenges in cloud-native architecture: the efficient management of dynamic, stateful, and performance-sensitive workloads. For organizations running mission-critical JVM applications or large-scale databases, version 1.35 offers a path to zero-downtime scaling and vastly improved hardware efficiency.&lt;/p&gt;
&lt;p&gt;As the &amp;quot;Timbernetes&amp;quot; release settles into the ecosystem, the focus shifts from simply managing pod existence to optimizing pod performance in real-time. The integration of VPA, the safeguards for QoS and memory shrinking, and the introduction of pod-level sharing all point toward a future where the infrastructure is truly invisible, responding elastically to the heartbeat of the application. For architects and operators, the message of Kubernetes 1.35 is clear: the era of the &amp;quot;restart tax&amp;quot; is over, and the era of fluid, high-utilization clusters has arrived.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Kubernetes 1.35: In-Place Pod Resize Graduates to Stable, accessed on December 29, 2025, &lt;a href=&quot;https://kubernetes.io/blog/2025/12/19/kubernetes-v1-35-in-place-pod-resize-ga/&quot;&gt;https://kubernetes.io/blog/2025/12/19/kubernetes-v1-35-in-place-pod-resize-ga/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resize CPU and Memory Resources assigned to Containers - Kubernetes, accessed on December 29, 2025, &lt;a href=&quot;https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/&quot;&gt;https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vertical Pod Autoscaling - Kubernetes, accessed on December 29, 2025, &lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/autoscaling/vertical-pod-autoscale/&quot;&gt;https://kubernetes.io/docs/concepts/workloads/autoscaling/vertical-pod-autoscale/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kubernetes 1.35 &amp;quot;Timbernetes&amp;quot; Introduces Vertical Scaling - The New Stack, accessed on December 29, 2025, &lt;a href=&quot;https://thenewstack.io/kubernetes-1-35-timbernetes-introduces-vertical-scaling/&quot;&gt;https://thenewstack.io/kubernetes-1-35-timbernetes-introduces-vertical-scaling/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kubernetes 1.35 - Kubesimplify, accessed on December 29, 2025, &lt;a href=&quot;https://blog.kubesimplify.com/kubernetes-v135-whats-new-whats-changing-and-what-you-should-know?source=more_articles_bottom_blogs&quot;&gt;https://blog.kubesimplify.com/kubernetes-v135-whats-new-whats-changing-and-what-you-should-know?source=more_articles_bottom_blogs&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kubernetes In-Place Pod Resizing - Vertical Scaling Without Downtime, accessed on December 29, 2025, &lt;a href=&quot;https://builder.aws.com/content/30MCh47Lw54JPCwGh0TKZgJU8d7/kubernetes-in-place-pod-resizing-vertical-scaling-without-downtime&quot;&gt;https://builder.aws.com/content/30MCh47Lw54JPCwGh0TKZgJU8d7/kubernetes-in-place-pod-resizing-vertical-scaling-without-downtime&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In-place Pod resizing in Kubernetes: How it works and how to use it | Tech blog - Palark, accessed on December 29, 2025, &lt;a href=&quot;https://palark.com/blog/in-place-pod-resizing-kubernetes/&quot;&gt;https://palark.com/blog/in-place-pod-resizing-kubernetes/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kubernetes 1.35 enables zero-downtime resource scaling for production cloud workloads, accessed on December 29, 2025, &lt;a href=&quot;https://www.networkworld.com/article/4107891/kubernetes-1-35-enables-zero-downtime-resource-scaling-for-production-cloud-workloads.html&quot;&gt;https://www.networkworld.com/article/4107891/kubernetes-1-35-enables-zero-downtime-resource-scaling-for-production-cloud-workloads.html&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;KEP-2837: Pod Level Resource Specifications - GitHub, accessed on December 29, 2025, &lt;a href=&quot;https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/2837-pod-level-resource-spec/README.md&quot;&gt;https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/2837-pod-level-resource-spec/README.md&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In-Place Vertical Pod Scaling: The Future of Resource Management, accessed on December 29, 2025, &lt;a href=&quot;https://superorbital.io/blog/in-place-vertical-pod-scaling/&quot;&gt;https://superorbital.io/blog/in-place-vertical-pod-scaling/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kubernetes In-Place Pod Vertical Scaling - ScaleOps, accessed on December 29, 2025, &lt;a href=&quot;https://scaleops.com/blog/kubernetes-in-place-pod-vertical-scaling/&quot;&gt;https://scaleops.com/blog/kubernetes-in-place-pod-vertical-scaling/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Best Practices for configuring the JVM in a Kubernetes environment | AWS Builder Center, accessed on December 29, 2025, &lt;a href=&quot;https://builder.aws.com/content/2y4rrgs9rUiiyBZsR2TVLmGhNS3/best-practices-for-configuring-the-jvm-in-a-kubernetes-environment&quot;&gt;https://builder.aws.com/content/2y4rrgs9rUiiyBZsR2TVLmGhNS3/best-practices-for-configuring-the-jvm-in-a-kubernetes-environment&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Kubernetes</category><category>DevOps</category><category>Cloud Computing</category><category>Infrastructure</category><category>Platform Engineering</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0089-kubernetes-1-35-in-place-pod-vertical-scaling-guide/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Taming the Chaos: Let&apos;s Sort Out Those Flaky CI/CD Pipelines</title><link>https://mkabumattar.com/blog/post/troubleshooting-flaky-ci-cd-pipelines/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/troubleshooting-flaky-ci-cd-pipelines/</guid><description>Learn practical strategies for troubleshooting and preventing flaky CI/CD pipelines. Identify common causes, use debugging tools like GitHub Actions and act, and implement best practices for a more stable development workflow.</description><pubDate>Sun, 28 Dec 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ever get super frustrated with your CI/CD pipeline? You know, the one that sometimes works perfectly and other times just throws a random tantrum? You push your code, the pipeline starts doing its thing, and you&amp;#39;re crossing your fingers for that sweet green light. But then, bam! A failure pops up out of nowhere, and you&amp;#39;re stuck spending hours trying to figure out why, only for it to maybe disappear on the next try. If that sounds familiar, you&amp;#39;re not alone. These unreliable, on-again-off-again pipelines are what we call &amp;quot;flaky.&amp;quot; And honestly, they can really mess with how productive you are, make you doubt your tests, and just slow everything down. So, how do we get a grip on this mess and build CI/CD pipelines we can actually count on?&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What&amp;#39;s the Deal with &amp;quot;Flaky&amp;quot; CI/CD Pipelines Anyway?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Often, when a CI/CD pipeline&amp;#39;s acting flaky, it boils down to something called a flaky test. These are tests that just can&amp;#39;t make up their mind. They&amp;#39;ll pass one time and then fail the next, even if you haven&amp;#39;t touched the code or the test itself. There are a bunch of reasons why this happens. Maybe the environment&amp;#39;s a bit off, or the test data isn&amp;#39;t getting refreshed properly between runs. Sometimes it&amp;#39;s about timing or even the time zone, and other times it&amp;#39;s because the tests depend on each other in a weird way.&lt;/p&gt;
&lt;p&gt;When these flaky tests sneak into your automated CI/CD pipeline, that&amp;#39;s when you get a flaky pipeline. The whole thing might fail now and then, not because there&amp;#39;s a real problem with your code, but just because these tests are so unpredictable, or something else in the pipeline is acting up. It can be a real pain, causing builds to fail for no good reason and holding up your software releases. The big issue with flakiness is that you just can&amp;#39;t predict it. It makes it super hard to tell if a pipeline failure means you&amp;#39;ve actually got a bug in your software or if it&amp;#39;s just a temporary hiccup.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why Should You Even Bother Fixing Flaky Pipelines? Trust Me, It&amp;#39;s Worth It&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Ignoring flaky pipelines can really bite you in the long run, messing with your development process and the quality of your software. One of the first things you&amp;#39;ll notice is that development and releases start taking longer. When pipelines fail sometimes, developers often have to run them over and over to make sure the failure&amp;#39;s real, which wastes a lot of time and delays getting new stuff or bug fixes out the door.&lt;/p&gt;
&lt;p&gt;Plus, flaky pipelines seriously damage the trust you have in your test results and the whole CI/CD thing. If tests keep failing for reasons that have nothing to do with your code, the team might start to think the automated tests aren&amp;#39;t reliable. This can lead to a lot of extra debugging as developers chase down errors that are random and hard to recreate. Sometimes, all the noise from flaky failures can even hide real problems, letting actual bugs slip into production. And all that time spent looking into these false alarms? That adds up in maintenance costs too. Ultimately, if you&amp;#39;ve got flaky pipelines, it makes it really tough to achieve true continuous deployment, where you&amp;#39;re releasing software frequently and reliably. It&amp;#39;s hard to fully automate the deployment process when you don&amp;#39;t trust the pipeline&amp;#39;s stability.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;The Usual Suspects: What&amp;#39;s Commonly Causing Flaky Behavior in CI/CD?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Figuring out what usually causes flakiness is the first step in being able to troubleshoot and stop it from happening. One common culprit is &lt;strong&gt;concurrency issues&lt;/strong&gt;. When tests run at the same time, they might fight over the same resources, leading to race conditions or deadlocks that cause things to go wrong in unpredictable ways.&lt;/p&gt;
&lt;p&gt;Another big reason for flakiness is &lt;strong&gt;external dependencies&lt;/strong&gt;. If your tests rely on outside systems like APIs, databases, or network services, they can fail now and then because of network delays, downtime, or just different response times from these services. &lt;strong&gt;Timing and synchronization problems&lt;/strong&gt; are also pretty common. Tests might fail if they don&amp;#39;t wait long enough for things to finish happening in the background, or if they expect things to take a specific amount of time that isn&amp;#39;t always guaranteed. Timeouts, while they&amp;#39;re needed, can also cause flakiness if they&amp;#39;re set too short for certain situations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Non-deterministic logic&lt;/strong&gt; in your tests or the application code can also lead to inconsistent results. If you&amp;#39;re relying on random stuff like dates, times, or user input without controlling it properly, your tests might pass or fail without any real reason. Plus, an &lt;strong&gt;unstable test environment&lt;/strong&gt; is a major source of flakiness. If tests aren&amp;#39;t properly isolated from each other, if configurations are different across runs, or if you&amp;#39;re running into resource limits like not enough memory or CPU, that can all lead to intermittent failures. If one test leaves behind some state that affects the next one, that can also cause unexpected behavior. Finally, &lt;strong&gt;test order dependency&lt;/strong&gt;, where whether a test passes depends on which tests ran before it, is another common cause of flakiness. And let&amp;#39;s not forget, poorly written tests with not enough checks or wrong assumptions can also contribute to the problem.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Detective Mode: How Do You Actually Find Those Flaky Tests in Your CI/CD Pipeline?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Finding flaky tests takes a careful approach and often means using the tools your CI/CD system gives you. One basic thing to do is &lt;strong&gt;look at your past test results&lt;/strong&gt;. By checking the logs from previous pipeline runs, you can look for tests that have a pattern of passing and failing without any changes to the code. A lot of CI/CD tools even have &lt;strong&gt;built-in features to detect flaky tests&lt;/strong&gt; that can automatically flag tests that act inconsistently based on their history.&lt;/p&gt;
&lt;p&gt;Another good way is to &lt;strong&gt;run tests multiple times&lt;/strong&gt; under the exact same conditions. If a test passes sometimes and fails other times without any changes, that&amp;#39;s a pretty clear sign it&amp;#39;s flaky. &lt;strong&gt;Keeping track of and writing down&lt;/strong&gt; the history of your test runs, including how often they fail and in what patterns, can also help you spot the unreliable ones. When you think a specific test might be flaky, &lt;strong&gt;try running it by itself&lt;/strong&gt; multiple times to see if the flakiness is really in that test or if something else is influencing it. Lastly, using &lt;strong&gt;test retrying plugins and frameworks&lt;/strong&gt; can help you find them. If a test fails the first time but then passes on an automatic retry, it&amp;#39;s likely flaky. There are also special tools out there designed to analyze test patterns and find flakiness, and they can be really helpful.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Uh Oh, It Failed... Now What? A Practical Guide to Troubleshooting Flaky Pipelines&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When your CI/CD pipeline fails and you think it&amp;#39;s because of a flaky test, you need a plan for figuring out what&amp;#39;s going on. First, &lt;strong&gt;take a look at the logs and outputs&lt;/strong&gt; from the failed pipeline run. Check the error messages, stack traces, and anything else that might give you a hint about why it failed. Sometimes, making your pipeline logging more detailed can reveal more about what went wrong.&lt;/p&gt;
&lt;p&gt;Next, try to &lt;strong&gt;isolate the test&lt;/strong&gt; that failed and run it on its own, both on your computer and in the CI environment if you can. The goal here is to &lt;strong&gt;make the failure happen on your own machine&lt;/strong&gt;. Tools like Docker or act can be super useful for recreating the CI environment on your local machine, including all the specific things it depends on and how it&amp;#39;s set up. Carefully &lt;strong&gt;compare the differences&lt;/strong&gt; between your local setup and the CI/CD environment. Make sure &lt;strong&gt;all the dependency versions&lt;/strong&gt; are the same in both places. Also, &lt;strong&gt;check your CI/CD configuration files&lt;/strong&gt; for any mistakes or incorrect settings that might be causing the flakiness.&lt;/p&gt;
&lt;p&gt;Using the debugging tools that your CI/CD platform or testing framework provides can be really helpful. Some platforms even let you SSH into the CI runner to look around and debug things directly. Finally, pay close attention to any potential &lt;strong&gt;timing and concurrency&lt;/strong&gt; issues. Look for race conditions or synchronization problems in your code or tests, especially if the failures seem to happen more often when things are busy or running in parallel.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Prevention is Better Than Cure: Smart Ways to Keep Flakiness Out of Your CI/CD Setup&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The best way to deal with flaky pipelines is to stop them from happening in the first place. This starts with &lt;strong&gt;writing tests that you can trust&lt;/strong&gt;. Make your tests small, focused, and predictable, and don&amp;#39;t use any logic that&amp;#39;s not deterministic. &lt;strong&gt;Keeping test environments isolated&lt;/strong&gt; is also key. Use containerization (like Docker), virtualization, or temporary environments to make sure each test runs in a clean and consistent state without affecting other tests.&lt;/p&gt;
&lt;p&gt;Carefully &lt;strong&gt;manage external dependencies&lt;/strong&gt; by using mocks, stubs, or fakes to pretend to be the external services. This makes your tests less dependent on whether those services are available and stable. When you&amp;#39;re dealing with &lt;strong&gt;asynchronous operations&lt;/strong&gt;, use proper ways to wait and synchronize things, like explicit waits and timeouts, instead of just guessing how long to wait. Be careful about &lt;strong&gt;test order&lt;/strong&gt; and don&amp;#39;t create tests that rely on what happened in previous tests. You might even want to try running your tests in a random order to see if you uncover any hidden dependencies. Use &lt;strong&gt;consistent test data&lt;/strong&gt; so you don&amp;#39;t get different results each time. Finally, make sure you &lt;strong&gt;regularly maintain your tests&lt;/strong&gt; by reviewing them, cleaning them up, and getting rid of any that are no longer needed. Treat your test code with the same care you give your application code, and make sure it goes through code reviews too.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;When Things Get Tricky: Using Retry Mechanisms for Those Random Failures&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Even if you do everything right, sometimes you&amp;#39;ll still get tests that fail now and then for no clear reason. In these cases, &lt;strong&gt;retry mechanisms&lt;/strong&gt; can be helpful. A lot of CI/CD tools and testing frameworks let you automatically retry failed tests. You can often set it up to only retry based on certain types of errors, like network issues, and you can limit how many times it retries to avoid getting stuck in a loop.&lt;/p&gt;
&lt;p&gt;But remember, retries should be a temporary fix while you figure out why the test is flaky, not a permanent solution. Relying too much on retries can hide real problems and make your system less stable in the long run. It&amp;#39;s important to know the difference between a real failure and a flaky one, and only retry tests that you suspect are flaky. Tools like TestNG&amp;#39;s IRetryAnalyzer and Jest&amp;#39;s retry configuration give you ways to implement retry logic in your tests.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Keep an Eye On Things: Why Logging and Monitoring Your CI/CD Pipeline Health Matters&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Logging and monitoring&lt;/strong&gt; your CI/CD pipeline are super important for finding and fixing flaky tests and other problems early on. Make sure you&amp;#39;re logging everything important in your pipeline, like each step, the test results, and any relevant info about the environment. Keep an eye on key metrics like how long builds take, how often tests pass, and how frequently you&amp;#39;re deploying. This helps you spot trends and anything unusual. Set up alerts to let your team know if something fails or if there&amp;#39;s any weird behavior in the pipeline.&lt;/p&gt;
&lt;p&gt;Use dashboards to see the health of your pipeline at a glance and make it easier to find patterns or recurring issues. Look at your logs to understand why things are failing. You might even want to use AI-powered tools that can help you analyze a lot of log data and find the root causes of pipeline failures more quickly. If you&amp;#39;re monitoring things proactively, you can catch flaky tests early, before they cause big problems for your development process. Tools like Datadog and Grafana offer good ways to monitor and get alerts for your CI/CD pipelines.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;A Real-World Example: Debugging Flaky Pipelines with GitHub Actions and act&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s see how you might troubleshoot flaky pipelines if you&amp;#39;re using GitHub Actions. If you think a workflow is failing sometimes for no reason, the first thing to do is usually turn on &lt;strong&gt;debug logging&lt;/strong&gt;. You can do this by setting the secret ACTIONS_RUNNER_DEBUG or the variable ACTIONS_STEP_DEBUG to true in your repository settings. This will give you more detailed logs during your workflow runs, which can help you understand what&amp;#39;s happening and where things might be going wrong.&lt;/p&gt;
&lt;p&gt;To make debugging faster, you can use act, a tool you can run from your command line that lets you run your GitHub Actions workflows on your own computer. After you install act, you can go to your repository in your terminal and run the command act. This will pretend to be a GitHub Actions run on your local machine, using Docker containers to run the workflow steps. This way, you can try to recreate the failing workflow locally without having to push code changes over and over. You can look at the logs that act generates to see where it&amp;#39;s failing. You can also set environment variables and secrets using the -s flag or a .env file to make your local environment more like your GitHub Actions environment.&lt;/p&gt;
&lt;p&gt;For more direct debugging in GitHub Actions, you can use actions like mxschmitt/action-tmate. This action lets you create a secure SSH connection to the runner environment where your workflow is running, so you can look at files, run commands, and debug things in real-time.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions (FAQ) - Your Burning Questions About Flaky CI/CD Pipelines Answered&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the most common things that make tests flaky?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Flaky tests often happen because of concurrency issues, relying on external stuff that&amp;#39;s not always stable, timing and synchronization problems, logic that&amp;#39;s not predictable, test environments that aren&amp;#39;t stable, and tests that depend on the order they run in.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can I find flaky tests in my GitLab CI/CD pipeline?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitLab CI/CD has features to help you spot flaky tests. You can look at the pipeline success and duration charts to find jobs that fail randomly. GitLab also lets you set up automatic retries for tests that fail, and if a test passes on a retry, it can be marked as potentially flaky. Plus, you can use the CI Lint tool to check your pipeline configuration for any potential issues.71 For more advanced tracking, you might want to connect with tools that offer specific flaky test detection and reporting within GitLab.72&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some ways to deal with external dependencies in tests?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;A good way is to use mocks, stubs, or fakes to simulate how external things like APIs or databases behave. This keeps your tests from relying on whether those external systems are working. You can also use dependency injection to easily swap out the real dependencies with test doubles. For integration tests where you do need to talk to real external systems, think about using dedicated test accounts or controlled datasets to minimize interference.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can I make my test isolation better in my CI/CD pipeline?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Use containerization technologies like Docker to create isolated and consistent test environments for each pipeline run. Make sure your tests don&amp;#39;t depend on shared states and that you&amp;#39;re setting up and cleaning up anything needed within each test&amp;#39;s scope.4 If you&amp;#39;re working with databases, consider using database transaction rollbacks or dedicated cleanup jobs to make sure you start with a clean slate before each test.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Is it okay to just retry flaky tests?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;While retrying flaky tests might make your CI/CD pipeline seem more stable for a bit, it&amp;#39;s not a good long-term fix. Retries just hide the real problems causing the flakiness and can give you a false sense of security. It&amp;#39;s important to find out why the tests are flaky and fix them properly. Retries should only be used carefully as a short-term solution while you&amp;#39;re working on the underlying issues.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;Conclusion: Let&amp;#39;s Get Stable - Building Solid CI/CD Pipelines for Reliable Software&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Flaky CI/CD pipelines can really get in the way of delivering software efficiently and reliably. But by understanding what causes this flakiness, using good ways to find and fix it, and following best practices to prevent it, you can make your pipelines much more stable. Remember, it&amp;#39;s important to be proactive about test reliability and the health of your CI/CD pipeline. While tools like GitHub Actions and act are great for building and debugging your pipelines, the real key to getting things under control is writing solid, isolated tests and keeping your CI/CD environment well-monitored and consistent. A stable CI/CD pipeline means faster release cycles, better quality software, and more confidence for your development team.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jetbrains.com/teamcity/ci-cd-guide/concepts/flaky-tests/&quot;&gt;What are Flaky Tests? | TeamCity CI/CD Guide - JetBrains&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/pipelines/test/flaky-test-management?view=azure-devops&quot;&gt;Manage flaky tests - Azure Pipelines | Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devops.com/a-deep-dive-into-flaky-tests/&quot;&gt;A Deep Dive Into Flaky Tests - DevOps.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.testrail.com/blog/flaky-tests/&quot;&gt;How to Identify, Fix, and Prevent Flaky Tests - TestRail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://buildkite.com/resources/blog/understanding-flaky-tests/&quot;&gt;Understanding flaky tests and how to deal with them - Buildkite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://circleci.com/blog/reducing-flaky-test-failures/&quot;&gt;How to reduce flaky test failures - CircleCI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.launchableinc.com/blog/handling-flaky-tests-reducing-the-noise-in-ci-cd-pipeline/&quot;&gt;Handling Flaky Tests: Reducing the Noise in CI/CD Pipeline - Launchable Inc.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/playwright/how-to-reproduce-ci-failures-locally-in-playwright-lfl&quot;&gt;How to Reproduce CI Failures Locally in Playwright - DEV Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mxschmitt.github.io/action-tmate/&quot;&gt;Debug your GitHub Actions by using tmate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.codemancers.com/blog/2024-03-19-act-guide-for-github-workflow&quot;&gt;Running GitHub Actions Locally with act - A Comprehensive Guide - Codemancers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semaphoreci.com/blog/flaky-tests-mitigation&quot;&gt;Best Practices for Identifying and Mitigating Flaky Tests - Semaphore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.datadoghq.com/blog/best-practices-for-monitoring-software-testing/&quot;&gt;Best practices for monitoring software testing in CI/CD - Datadog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://digital.ai/catalyst-blog/cicd-pipeline-best-practices/&quot;&gt;CI/CD Pipeline Best Practices | Blog - Digital.ai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/monitoring-workflows&quot;&gt;Monitoring workflows - GitHub Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.browserstack.com/guide/test-github-actions-locally&quot;&gt;How to test GitHub Actions locally? - BrowserStack&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>CI/CD</category><category>Testing</category><category>DevOps</category><category>Automation</category><category>Pipeline Reliability</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0088-troubleshooting-flaky-ci-cd-pipelines/hero.jpg" length="0" type="image/jpeg"/></item><item><title>The Democratization of Container Security: Docker Hardened Images</title><link>https://mkabumattar.com/blog/post/democratization-docker-hardened-images-container-security/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/democratization-docker-hardened-images-container-security/</guid><description>Explore how Docker democratized container security by open-sourcing 1,000+ Hardened Images under Apache 2.0. Learn about distroless containers, 95% smaller attack surfaces, SBOM/VEX integration, and how to migrate to secure-by-default images using multi-stage builds.</description><pubDate>Fri, 19 Dec 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On December 17, 2025, the world of container security changed in a big way. Docker decided to open up its entire catalog of over 1,000 Docker Hardened Images (DHI) to everyone under the Apache 2.0 license. This isn&amp;#39;t just a small update. It&amp;#39;s a move away from the old &amp;quot;pay-to-play&amp;quot; security model where only big companies with deep pockets could afford the best protection. Now, whether you&amp;#39;re a hobbyist working on a weekend project or a dev at a massive agency, you&amp;#39;ve got access to the same high-tier security. With supply chain attacks expected to cost businesses around $60 billion this year, this shift is more than welcome. Let’s break down what this means for you and your DevSecOps workflow.&lt;/p&gt;
&lt;h2&gt;What sparked this massive change in how Docker handles security?&lt;/h2&gt;
&lt;p&gt;For a long time, the industry has been stuck in what people call the &amp;quot;Supply Chain Paradox.&amp;quot; We all use open source because it&amp;#39;s fast and powerful, but keeping it secure is a nightmare. Most devs pull a community image, run a scan, and then get hit with a wall of red alerts. You&amp;#39;d spend your whole afternoon trying to patch vulnerabilities you didn&amp;#39;t even know were there. Historically, the &amp;quot;clean&amp;quot; base images the ones that were already patched and minimal were locked behind expensive enterprise walls.&lt;/p&gt;
&lt;p&gt;Docker realized that container images are the perfect place to fix this. They&amp;#39;re the delivery trucks for your code. By making these images free and open source, Docker is making it so that the &amp;quot;right way&amp;quot; to do things is also the &amp;quot;easy way.&amp;quot; By using the Apache 2.0 license, they&amp;#39;ve also removed the fear of being locked into one vendor. It&amp;#39;s a foundational shift that treats security as a basic right rather than a luxury add-on.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;The Old Way (Pay-to-Play)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;The New Way (Democratized)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;High-tier images were for big spenders only&lt;/td&gt;
&lt;td&gt;Everyone gets 1,000+ images for free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community images came with high CVE debt&lt;/td&gt;
&lt;td&gt;Images start with near-zero CVEs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proprietary licenses limited how you used them&lt;/td&gt;
&lt;td&gt;Apache 2.0 license means you can use them anywhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security was a premium feature you added later&lt;/td&gt;
&lt;td&gt;Security is built in from the start&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;How do these hardened images actually change the game for container security?&lt;/h2&gt;
&lt;p&gt;Usually, when we talk about container security, we think about firewalls or monitoring things while they run. Docker Hardened Images take a different path by focusing on &amp;quot;shifting left.&amp;quot; This means they bake security right into the image before it even leaves your machine. These aren&amp;#39;t just standard images with a few updates. They&amp;#39;re built using a &amp;quot;distroless&amp;quot; philosophy.&lt;/p&gt;
&lt;p&gt;The idea is simple: if it&amp;#39;s not there, an attacker can&amp;#39;t use it. Most standard images are full of extra stuff like shells, package managers, and various utilities. They&amp;#39;re handy for debugging, but they&amp;#39;re a gift to a hacker. By stripping all that out, Docker Hardened Images end up with an attack surface that&amp;#39;s about 95% smaller than traditional community images.&lt;/p&gt;
&lt;h2&gt;Why is supply chain security the biggest topic in DevSecOps right now?&lt;/h2&gt;
&lt;p&gt;Almost every app today is built on a mountain of open source parts. In fact, research shows about 90% of modern software relies on them. When you pull a random image from a public registry, you&amp;#39;re essentially trusting thousands of lines of code from people you don&amp;#39;t know. It’s a huge, invisible risk.&lt;/p&gt;
&lt;p&gt;Docker Hardened Images fix this by giving you a &amp;quot;receipt&amp;quot; for everything inside Every image comes with a Software Bill of Materials (SBOM), which is just a list of every single package and library in the container. They also follow SLSA (pronounced &amp;quot;salsa&amp;quot;) Level 3 standards. This basically proves the image was built in a secure way and hasn&amp;#39;t been tampered with. It&amp;#39;s all about moving from &amp;quot;I hope this is safe&amp;quot; to &amp;quot;I know this is safe.&amp;quot;&lt;/p&gt;
&lt;h2&gt;What&amp;#39;s the secret to that 95% smaller attack surface?&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s all about minimalism. Think about a standard image as a house with ten doors and twenty windows. It&amp;#39;s easy to get into, but it&amp;#39;s also easy for a thief to break in. A hardened image is like a house with just one solid door.&lt;/p&gt;
&lt;p&gt;In the security world, hackers love &amp;quot;Living off the Land.&amp;quot; This means they use the tools already inside your container (like curl or sh) to download malware or move around your network. Hardened images remove those tools in the production version. You get the app and its direct dependencies, and that&amp;#39;s it. No shell, no package manager, no extra doors for hackers to kick down.&lt;/p&gt;
&lt;h2&gt;How do SBOM and VEX data help you stop chasing &amp;quot;ghost&amp;quot; vulnerabilities?&lt;/h2&gt;
&lt;p&gt;If you&amp;#39;ve ever used a vulnerability scanner, you know the pain of &amp;quot;alert fatigue.&amp;quot; You get a report with 500 &amp;quot;High&amp;quot; vulnerabilities, but half of them don&amp;#39;t even matter because the vulnerable code isn&amp;#39;t actually being used. It&amp;#39;s just noise.&lt;/p&gt;
&lt;p&gt;This is where VEX (Vulnerability Exploitability eXchange) comes in. It&amp;#39;s a way for Docker to tell your scanner: &amp;quot;Yeah, that library is there, but we&amp;#39;ve hardened the image so it can&amp;#39;t actually be exploited.&amp;quot; When you combine that with the fact that these images start with near-zero CVEs, your security team can finally focus on the real problems instead of wasting time on false alarms.&lt;/p&gt;
&lt;h2&gt;What&amp;#39;s the real difference between DHI Free vs Enterprise?&lt;/h2&gt;
&lt;p&gt;Even though the images are free, there&amp;#39;s still a reason a big company might want the enterprise tier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DHI Free&lt;/strong&gt; is perfect for individuals or smaller teams. You get all 1,000+ images, the Apache 2.0 license, and all the core security data like SBOMs and SLSA provenance. It&amp;#39;s everything you need to build a safe app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DHI Enterprise&lt;/strong&gt; is for organizations that need guarantees. The biggest perk here is a 7-day SLA for critical patches. If a huge bug is found, Docker commits to fixing it in a week (and they&amp;#39;re aiming for 24 hours). You also get variants that meet government standards like FIPS and STIG, plus &amp;quot;Extended Lifecycle Support&amp;quot; (ELS) which keeps old software secure for five extra years after it&amp;#39;s officially retired.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;DHI Free&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;DHI Enterprise&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Catalog Access&lt;/td&gt;
&lt;td&gt;1,000+ images&lt;/td&gt;
&lt;td&gt;1,000+ plus special variants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patching Speed&lt;/td&gt;
&lt;td&gt;Best effort&lt;/td&gt;
&lt;td&gt;7-day contractual SLA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance&lt;/td&gt;
&lt;td&gt;Core security metadata&lt;/td&gt;
&lt;td&gt;FIPS and STIG-ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long-term Support&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;5 extra years of patches&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;How do you actually work without a shell in your container?&lt;/h2&gt;
&lt;p&gt;Switching to a hardened image can be a bit of a shock if you&amp;#39;re used to &amp;quot;exec-ing&amp;quot; into a running container to poke around. Since there&amp;#39;s no shell, you can&amp;#39;t just run &lt;code&gt;docker exec -it my_container /bin/bash&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The best way to handle this is through multi-stage builds. You use a -dev version of the image to build your app (which &lt;em&gt;does&lt;/em&gt; have a shell and tools), then copy only the final binary into the &lt;code&gt;-runtime&lt;/code&gt; version for production.&lt;/p&gt;
&lt;p&gt;Here’s a quick look at how that looks in a Dockerfile:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;# Stage 1: Build your app in a &amp;#39;dev&amp;#39; image that has a shell and tools
FROM docker.io/docker/hardened-python:3.13-dev AS builder
WORKDIR /app
COPY requirements.txt.
# We can use &amp;#39;pip&amp;#39; here because it&amp;#39;s the dev variant
RUN pip install --no-cache-dir -r requirements.txt
COPY..

# Stage 2: Move the final app to the &amp;#39;hardened&amp;#39; runtime image
# This version has no shell and near-zero CVEs
FROM docker.io/docker/hardened-python:3.13
WORKDIR /app
# Copy the installed packages from the builder stage
COPY --from=builder /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages
COPY --from=builder /app /app

# Run the app directly (no shell needed)
USER nonroot
ENTRYPOINT [&amp;quot;python&amp;quot;, &amp;quot;main.py&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you really need to debug something in production, you can use &lt;strong&gt;Docker Debug&lt;/strong&gt;. It attaches a temporary shell to the container from the outside without breaking the security of the image itself.&lt;/p&gt;
&lt;h2&gt;Does using these images mean you&amp;#39;re stuck with Docker forever?&lt;/h2&gt;
&lt;p&gt;One of the best things about this move is that it actually helps you avoid vendor lock-in. Because Docker chose the Apache 2.0 license, you&amp;#39;re free to use these images anywhere Google Cloud, AWS, Kubernetes, you name it.&lt;/p&gt;
&lt;p&gt;They also built these on top of familiar distributions like Debian and Alpine instead of making up their own proprietary OS. Everything is standard OCI (Open Container Initiative) format, so it works with all your existing tools. It&amp;#39;s a &amp;quot;no-strings-attached&amp;quot; way to get better security.&lt;/p&gt;
&lt;h2&gt;How is AI helping with the switch to hardened images?&lt;/h2&gt;
&lt;p&gt;Migrating hundreds of legacy containers to a new base image sounds like a lot of work. Docker is using AI to make it easier. Their &lt;strong&gt;Docker AI Assistant&lt;/strong&gt; can actually scan your current images and tell you exactly which hardened version you should switch to.&lt;/p&gt;
&lt;p&gt;It can even help you update your Dockerfiles or figure out why something might break in a &amp;quot;no-shell&amp;quot; environment. They&amp;#39;re even applying this hardening to AI infrastructure itself, like &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; servers, so you can build secure AI agents from day one&lt;/p&gt;
&lt;p&gt;Here’s a simple example of how you might use one of those hardened servers in a &lt;code&gt;compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;services:
  # A hardened MongoDB server for an AI agent
  database:
    image: docker.io/docker/hardened-mongodb:latest
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD_FILE=/run/secrets/db_password
    secrets:
      - db_password
    # Hardened images run as non-root by default
    security_opt:
      - no-new-privileges:true

secrets:
  db_password: file:./password.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Common Questions (FAQ)&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What exactly are Docker Hardened Images?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;They&amp;#39;re ultra-minimal, production-ready base images. Docker takes popular images, strips out everything you don&amp;#39;t need, patches all the bugs, and gives you a clean foundation to build on.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Will my app break if I switch?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;It might, if your app depends on a shell command to start up. You&amp;#39;ll want to use multi-stage builds and test your app carefully. But once you get it working, you&amp;#39;ll have a much safer container.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Do I have to pay for these?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nope. The core catalog of 1,000+ images is free for everyone under the Apache 2.0 license. You only pay if you need specialized enterprise features like 7-day patching guarantees or government compliance.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Why are they better than standard images?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Standard images are built for convenience; hardened images are built for security. With a 95% smaller attack surface and near-zero CVEs, they&amp;#39;re much harder for a hacker to exploit.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do I find the right image?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just log into Docker Hub and look for the &amp;quot;Hardened Images&amp;quot; section. You&amp;#39;ll find everything from Node.js and Python to Nginx and MongoDB.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;A New Standard for the Industry&lt;/h2&gt;
&lt;p&gt;The move to make Docker Hardened Images free isn&amp;#39;t just a corporate update; it&amp;#39;s a reset for the whole industry. By making high-level security the default, Docker is helping every developer close the gap in their supply chain security. Yes, it takes a little bit of effort to move to a minimalist, &amp;quot;distroless&amp;quot; environment, but the payoff is huge. You get faster builds, fewer false alarms from your scanners, and a much tougher defense against attacks. In a world where security threats are growing every day, having a secure-by-default foundation is the best way to keep building with confidence.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Docker Makes Hardened Images Free Open and Transparent for Everyone, accessed December 19, 2025, &lt;a href=&quot;https://www.docker.com/press-release/docker-makes-hardened-images-free-open-and-transparent-for-everyone/&quot;&gt;https://www.docker.com/press-release/docker-makes-hardened-images-free-open-and-transparent-for-everyone/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Docker Hardened Images Official Documentation, accessed December 19, 2025, &lt;a href=&quot;https://docs.docker.com/dhi/&quot;&gt;https://docs.docker.com/dhi/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hardened Images Overview | Docker Docs, accessed December 19, 2025, &lt;a href=&quot;https://docs.docker.com/dhi/about/what/&quot;&gt;https://docs.docker.com/dhi/about/what/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unlimited access to Docker Hardened Images: Because security should be affordable, always, accessed December 19, 2025, &lt;a href=&quot;https://www.docker.com/blog/unlimited-access-to-docker-hardened-images-because-security-should-be-affordable-always/&quot;&gt;https://www.docker.com/blog/unlimited-access-to-docker-hardened-images-because-security-should-be-affordable-always/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hardened Container Images: Security Without Lock-in - Docker, accessed December 19, 2025, &lt;a href=&quot;https://www.docker.com/blog/hardened-container-images-security-vendor-lock-in/&quot;&gt;https://www.docker.com/blog/hardened-container-images-security-vendor-lock-in/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Docker Pushes Secure-by-Default Containers Into the Mainstream - theCUBE Research, accessed December 19, 2025, &lt;a href=&quot;https://thecuberesearch.com/docker-pushes-secure-by-default-containers-into-the-mainstream/&quot;&gt;https://thecuberesearch.com/docker-pushes-secure-by-default-containers-into-the-mainstream/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Docker Sets Free the Hardened Container Images - The New Stack, accessed December 19, 2025, &lt;a href=&quot;https://thenewstack.io/dockers-sets-free-the-hardened-container-images/&quot;&gt;https://thenewstack.io/dockers-sets-free-the-hardened-container-images/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Docker makes its entire catalog of security-hardened container images free for everyone - SiliconANGLE, accessed December 19, 2025, &lt;a href=&quot;https://siliconangle.com/2025/12/17/docker-open-sources-entire-catalog-hardened-images-making-free-everyone/&quot;&gt;https://siliconangle.com/2025/12/17/docker-open-sources-entire-catalog-hardened-images-making-free-everyone/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Securing the software supply chain shouldn&amp;#39;t be hard - Docker Blog, accessed December 19, 2025, &lt;a href=&quot;https://www.docker.com/blog/securing-the-software-supply-chain-shouldnt-be-hard-according-to-thecube-research-docker-makes-it-simple/&quot;&gt;https://www.docker.com/blog/securing-the-software-supply-chain-shouldnt-be-hard-according-to-thecube-research-docker-makes-it-simple/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Container Hardening: Securing your software supply chain - Chainguard, accessed December 19, 2025, &lt;a href=&quot;https://www.chainguard.dev/supply-chain-security-101/container-hardening-securing-your-software-supply-chain&quot;&gt;https://www.chainguard.dev/supply-chain-security-101/container-hardening-securing-your-software-supply-chain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Containers are the new Supply Chain Attack Vector - Docker, accessed December 19, 2025, &lt;a href=&quot;https://www.docker.com/resources/containers-are-the-new-supply-chain-attack-vector-on-demand-webinar/&quot;&gt;https://www.docker.com/resources/containers-are-the-new-supply-chain-attack-vector-on-demand-webinar/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Eliminate CVEs and Accelerate Builds: Attentive&amp;#39;s Results with Docker Hardened Images, accessed December 19, 2025, &lt;a href=&quot;https://www.docker.com/resources/building-faster-securing-smarter-attentive-docker-hardened-images-white-paper/&quot;&gt;https://www.docker.com/resources/building-faster-securing-smarter-attentive-docker-hardened-images-white-paper/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Docker</category><category>Container Security</category><category>DevSecOps</category><category>Supply Chain Security</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0087-democratization-docker-hardened-images-container-security/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Database DevOps: Making PostgreSQL and MongoDB CI/CD Feel Natural</title><link>https://mkabumattar.com/blog/post/database-devops-ci-cd-postgresql-mongodb/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/database-devops-ci-cd-postgresql-mongodb/</guid><description>Ready to ditch manual database updates? Learn how Database DevOps and CI/CD can transform PostgreSQL and MongoDB management for faster, more reliable releases.</description><pubDate>Fri, 05 Dec 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ever feel like your app deployments are super slick, but then you hit the database part, and things just... stop? It&amp;#39;s frustrating, right? You&amp;#39;ve got this smooth CI/CD pipeline for your code, but database updates can feel manual, risky, and just plain slow. That&amp;#39;s exactly where &lt;strong&gt;Database DevOps&lt;/strong&gt; comes in. It&amp;#39;s all about bringing that same speed, reliability, and ease you love about application CI/CD to your databases, whether you&amp;#39;re using &lt;strong&gt;PostgreSQL&lt;/strong&gt; or &lt;strong&gt;MongoDB&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Think of &lt;strong&gt;CI/CD&lt;/strong&gt; (Continuous Integration and Continuous Delivery/Deployment) as the engine of modern software development. It helps you integrate code changes often, test them thoroughly, and get them out the door without a ton of manual effort. Applying this to your databases isn&amp;#39;t just a nice-to-have anymore; it&amp;#39;s pretty much essential if you want to move fast and keep things stable. When you really embrace &lt;strong&gt;Database DevOps&lt;/strong&gt; and &lt;strong&gt;CI/CD&lt;/strong&gt; for your databases, you&amp;#39;ll see a ton of good things happen, making your development smoother and your apps more solid.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why Bother with Database CI/CD? What&amp;#39;s In It for You?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Seriously, there are some fantastic reasons to get your databases into the CI/CD flow. For starters, you can &lt;strong&gt;release new features way faster&lt;/strong&gt;. No more waiting around for someone to manually run database scripts. Getting updates out quickly can really give you a leg up on the competition. When you can react fast to what the market needs and what your users are saying, it makes a huge difference.&lt;/p&gt;
&lt;p&gt;Plus, automating database deployments means &lt;strong&gt;fewer errors and less downtime&lt;/strong&gt;. Let&amp;#39;s be honest, manual changes are just asking for trouble. One little typo, and you could have a big mess on your hands. Automation and good testing catch those slip-ups before they ever get near your live system, keeping everything running smoothly and reliably.&lt;/p&gt;
&lt;p&gt;It also really &lt;strong&gt;boosts how well teams work together&lt;/strong&gt;. Developers, operations folks, and database admins often feel like they&amp;#39;re on different islands. Database DevOps helps tear down those walls, encouraging everyone to share responsibility and talk to each other more. This better teamwork makes the whole process work better and helps you solve problems a lot quicker.&lt;/p&gt;
&lt;p&gt;And hey, keeping your data safe is a big deal, right? By building security checks right into your database change process – that&amp;#39;s often called &lt;strong&gt;DevSecOps&lt;/strong&gt; – you can &lt;strong&gt;improve data security and compliance&lt;/strong&gt;. You catch potential weak spots early on, instead of finding them after something&amp;#39;s already deployed. This proactive approach helps protect sensitive info and makes sure you&amp;#39;re following all the rules.&lt;/p&gt;
&lt;p&gt;Even if you&amp;#39;re dealing with &lt;strong&gt;older database systems&lt;/strong&gt;, you&amp;#39;re not left out. You can start small, automating parts of the process, and gradually bring those legacy databases into a more modern workflow without causing chaos. Over time, they become easier to manage and adapt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Keeping an eye on things and making your database run better&lt;/strong&gt; is also a core part of this. With the right monitoring tools, you can see exactly what&amp;#39;s happening, spot potential issues before they become big problems, and make smart decisions to keep performance high.&lt;/p&gt;
&lt;p&gt;Automating those tedious, repetitive database tasks also &lt;strong&gt;makes your operations more efficient&lt;/strong&gt;. Your database admins and developers aren&amp;#39;t stuck doing boring manual work; they can focus on more important, interesting stuff. That&amp;#39;s a win for everyone.&lt;/p&gt;
&lt;p&gt;When you automate and standardize how you handle database changes, everything just becomes &lt;strong&gt;more reliable and higher quality&lt;/strong&gt;. You&amp;#39;re applying the same high standards and automated testing to your database changes as you do to your application code, which means deployments are more consistent and dependable. And that means a better experience for the people using your app.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What&amp;#39;s This Database DevOps Thing Really About? The Core Ideas.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;There are a few key ideas that really make Database DevOps tick. First off, you &lt;strong&gt;treat your database like code&lt;/strong&gt;. This means everything about your database – the structure, the scripts, the settings – goes into version control. Just like your app code! This way, you can see who changed what, work together easily, and quickly go back to an earlier version if something goes wrong.&lt;/p&gt;
&lt;p&gt;Next, you &lt;strong&gt;automate absolutely everything you can&lt;/strong&gt;. From setting up a new database to making changes, running tests, deploying, and even rolling back if needed – automation cuts down on human errors and speeds things up like crazy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Continuous Integration and Continuous Delivery (CI/CD)&lt;/strong&gt; are really the heart of it all. You want your database changes to flow through the same automated pipeline as your application changes. This keeps your database and your app in perfect sync.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Talking and working together&lt;/strong&gt; is huge. Breaking down those traditional barriers between development, operations, and database teams and getting everyone communicating openly is essential for hitting your goals and delivering value effectively.&lt;/p&gt;
&lt;p&gt;You also need to be &lt;strong&gt;constantly monitoring and getting feedback&lt;/strong&gt;. Having good monitoring tools gives you real-time insights into how your database is doing, helping you catch issues early. Plus, setting up feedback loops means teams can learn from each deployment and keep getting better.&lt;/p&gt;
&lt;p&gt;Finally, you &lt;strong&gt;bake security in right from the start&lt;/strong&gt; – that&amp;#39;s the &lt;strong&gt;Shift Left Security (DevSecOps)&lt;/strong&gt; idea. Instead of thinking about security as an afterthought, you build it into the database development process from day one. This helps prevent vulnerabilities and makes sure you&amp;#39;re compliant with regulations.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;CI/CD for PostgreSQL: Making Database Updates Smooth.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When you&amp;#39;re working with PostgreSQL, managing changes smoothly in a CI/CD pipeline often involves &lt;strong&gt;schema migrations&lt;/strong&gt;. This is how you update your database structure as your application evolves – things like adding new tables, changing existing ones, adding or removing columns, and tweaking indexes. A really popular tool for handling PostgreSQL schema migrations in a CI/CD setup is &lt;strong&gt;Liquibase&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Liquibase uses these things called &lt;strong&gt;changelogs&lt;/strong&gt;. They&amp;#39;re basically version-controlled files (you can write them in XML, YAML, JSON, or even plain SQL) that list all your database changes in the order they should happen. You keep these files in your version control system. Here&amp;#39;s a simple example of a Liquibase changelog that creates a users table and then adds an email column to it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;databaseChangeLog
  xmlns=&amp;quot;http://www.liquibase.org/xml/ns/dbchangelog&amp;quot;
  xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;
  xsi:schemaLocation=&amp;quot;http://www.liquibase.org/xml/ns/dbchangelog
         http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd&amp;quot;&amp;gt;
    &amp;lt;changeSet id=&amp;quot;create-users-table&amp;quot; author=&amp;quot;your-name&amp;quot;&amp;gt;
        &amp;lt;createTable tableName=&amp;quot;users&amp;quot;&amp;gt;
            &amp;lt;column name=&amp;quot;id&amp;quot; type=&amp;quot;INT&amp;quot; autoIncrement=&amp;quot;true&amp;quot;&amp;gt;
                &amp;lt;constraints primaryKey=&amp;quot;true&amp;quot; nullable=&amp;quot;false&amp;quot;/&amp;gt;
            &amp;lt;/column&amp;gt;
            &amp;lt;column name=&amp;quot;username&amp;quot; type=&amp;quot;VARCHAR(50)&amp;quot;&amp;gt;
                &amp;lt;constraints unique=&amp;quot;true&amp;quot; nullable=&amp;quot;false&amp;quot;/&amp;gt;
            &amp;lt;/column&amp;gt;
        &amp;lt;/createTable&amp;gt;
    &amp;lt;/changeSet&amp;gt;
    &amp;lt;changeSet id=&amp;quot;add-email-column&amp;quot; author=&amp;quot;your-name&amp;quot;&amp;gt;
        &amp;lt;addColumn tableName=&amp;quot;users&amp;quot;&amp;gt;
            &amp;lt;column name=&amp;quot;email&amp;quot; type=&amp;quot;VARCHAR(100)&amp;quot;/&amp;gt;
        &amp;lt;/addColumn&amp;gt;
    &amp;lt;/changeSet&amp;gt;
&amp;lt;/databaseChangeLog&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Liquibase works really well with popular CI/CD tools like Jenkins, GitLab CI, and GitHub Actions. You just add Liquibase commands to your pipeline scripts, and it&amp;#39;ll automatically apply those database changes whenever you deploy new application code. Plus, Liquibase has awesome &lt;strong&gt;rollback capabilities&lt;/strong&gt;. If something goes wrong, you can easily revert the database changes.&lt;/p&gt;
&lt;p&gt;While Liquibase is super popular, you&amp;#39;ve got other options for PostgreSQL schema migrations in CI/CD too, like &lt;strong&gt;Flyway&lt;/strong&gt; and &lt;strong&gt;pgroll&lt;/strong&gt;. Flyway is known for being straightforward and using versioned SQL scripts or Java code for migrations. pgroll is a bit different; it focuses on making schema changes with zero downtime by using virtual schemas built on top of your actual tables.&lt;/p&gt;
&lt;p&gt;To make CI/CD work well for your PostgreSQL databases, you should definitely put all your schema changes in version control, automate the migration process, test everything really well in environments that aren&amp;#39;t production, make sure your schema changes don&amp;#39;t break older versions of your app if possible, have solid plans for rolling back changes, automate the testing of your database changes, keep your database environments consistent across your pipeline, and always monitor how your database is doing after deployments.&lt;/p&gt;
&lt;p&gt;Here are some questions people often ask about PostgreSQL and Database DevOps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How often should I run database migrations?&lt;/strong&gt; You should ideally run them as part of your CI/CD pipeline whenever you have database schema changes that support new features or fix bugs. This keeps your database and application in sync.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What are the best tools for PostgreSQL schema migrations in a CI/CD pipeline?&lt;/strong&gt; Liquibase, Flyway, and pgroll are all great choices. The best one for you really depends on your specific needs and how complicated your migrations are.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How do I handle data changes when I change the schema?&lt;/strong&gt; You can include logic in your migration scripts to transform existing data to fit the new schema. This might mean adding default values to new columns or writing scripts to update data in existing ones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How can I make sure deployments with PostgreSQL schema changes don&amp;#39;t cause downtime?&lt;/strong&gt; You can make changes that are backward-compatible, use tools like pgroll, or use strategies like blue/green deployments where you run the new version alongside the old and gradually switch traffic over.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What&amp;#39;s the best way to undo PostgreSQL schema changes if something goes wrong?&lt;/strong&gt; Both Liquibase and Flyway have rollback features. You define rollback scripts in your changelogs or migration files that undo the changes made by a specific migration. You should automate these rollback procedures in your CI/CD pipeline.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;CI/CD for MongoDB: Automating Your NoSQL Changes.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Even though MongoDB is known for being flexible and not having a strict schema, you still need to manage database changes effectively in a DevOps setup. Your application probably expects data to be structured in a certain way, and changes to that structure need careful handling.&lt;/p&gt;
&lt;p&gt;Just like with PostgreSQL, there are tools to help you manage MongoDB changes in a CI/CD pipeline. &lt;strong&gt;Liquibase&lt;/strong&gt; has a MongoDB extension that lets you manage MongoDB schema changes and data migrations using the same ideas as with relational databases. Other tools made specifically for MongoDB migrations include &lt;strong&gt;migrate-mongo&lt;/strong&gt; and &lt;strong&gt;Mongock&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a simple example of a Liquibase MongoDB changelog that creates a products collection and adds a unique index to the name field:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;databaseChangeLog&amp;quot;: [
    {
      &amp;quot;changeSet&amp;quot;: {
        &amp;quot;id&amp;quot;: &amp;quot;create-products-collection&amp;quot;,
        &amp;quot;author&amp;quot;: &amp;quot;your-name&amp;quot;,
        &amp;quot;changes&amp;quot;: [
          {
            &amp;quot;createCollection&amp;quot;: {
              &amp;quot;collectionName&amp;quot;: &amp;quot;products&amp;quot;
            }
          }
        ]
      }
    },
    {
      &amp;quot;changeSet&amp;quot;: {
        &amp;quot;id&amp;quot;: &amp;quot;add-unique-index-to-product-name&amp;quot;,
        &amp;quot;author&amp;quot;: &amp;quot;your-name&amp;quot;,
        &amp;quot;changes&amp;quot;: [
          {
            &amp;quot;createIndex&amp;quot;: {
              &amp;quot;collectionName&amp;quot;: &amp;quot;products&amp;quot;,
              &amp;quot;keys&amp;quot;: {
                &amp;quot;name&amp;quot;: 1
              },
              &amp;quot;options&amp;quot;: {
                &amp;quot;unique&amp;quot;: true
              }
            }
          }
        ]
      }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Setting up a CI/CD pipeline for MongoDB means putting your MongoDB scripts (for things like creating collections, indexes, and transforming data) in version control, using a migration tool in your pipeline, automatically running these scripts when you deploy, testing data migrations and schema changes in non-production environments, and having ways to roll back both schema and data changes.&lt;/p&gt;
&lt;p&gt;Some good practices for MongoDB CI/CD include using scripts for all database changes, version controlling those scripts, testing migrations thoroughly in lower environments, automating the migration process in your CI/CD pipeline, having rollback plans, and always monitoring database performance.]&lt;/p&gt;
&lt;p&gt;Here are some common questions about MongoDB and Database DevOps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How do I manage schema changes in a schemaless database like MongoDB?&lt;/strong&gt; Even though MongoDB doesn&amp;#39;t enforce a strict schema, you can still manage the structure of your documents using migration tools to add, change, or remove fields, create indexes, and enforce validation rules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Are there specific tools for MongoDB schema migrations in CI/CD?&lt;/strong&gt; Yes, tools like Liquibase (with its MongoDB extension), migrate-mongo, and Mongock are designed for managing MongoDB schema and data changes in an automated and version-controlled way.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How do I handle data transformations when the MongoDB schema evolves?&lt;/strong&gt; Your migration scripts can include logic to change existing data to fit the new schema. This might mean renaming fields, changing data types, or restructuring documents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Can I use the same CI/CD pipeline for both PostgreSQL and MongoDB?&lt;/strong&gt; Absolutely! You can often use the same CI/CD setup for both, but you&amp;#39;ll need to use the right migration tools and scripts for each database type.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What are some of the unique challenges with MongoDB in a Database DevOps pipeline?&lt;/strong&gt; Some challenges include managing schema evolution in a schemaless environment, making sure data is consistent across documents, and handling data transformations during migrations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;Change Data Capture with Debezium: Getting Real-time Database Changes into Your Flow.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Debezium&lt;/strong&gt; is this fantastic open-source tool that lets you capture changes happening in your databases (like PostgreSQL and MongoDB) as they occur. It then sends these changes out as events to Apache Kafka. This is incredibly useful for automatically kicking off other processes or updating other systems right away when data in your main databases changes.&lt;/p&gt;
&lt;p&gt;Debezium works by using connectors for different databases that essentially watch the database&amp;#39;s transaction logs. When something changes – a row is added, updated, or deleted – the connector grabs that change and sends an event to a Kafka topic. Other apps can then listen to that topic and react. For instance, you could set up Debezium to watch your PostgreSQL orders table. When a new order comes in, Debezium sees it, sends an event to Kafka, and your order fulfillment system can immediately pick up that event and start processing the order.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a basic look at how you might set up Debezium for PostgreSQL using a JSON file. You&amp;#39;d typically send this kind of configuration to the Kafka Connect API:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;postgres-inventory-connector&amp;quot;,
  &amp;quot;config&amp;quot;: {
    &amp;quot;connector.class&amp;quot;: &amp;quot;io.debezium.connector.postgresql.PostgresConnector&amp;quot;,
    &amp;quot;database.hostname&amp;quot;: &amp;quot;your-postgres-host&amp;quot;,
    &amp;quot;database.port&amp;quot;: &amp;quot;5432&amp;quot;,
    &amp;quot;database.user&amp;quot;: &amp;quot;your-user&amp;quot;,
    &amp;quot;database.password&amp;quot;: &amp;quot;your-password&amp;quot;,
    &amp;quot;database.dbname&amp;quot;: &amp;quot;your-database&amp;quot;,
    &amp;quot;database.server.name&amp;quot;: &amp;quot;dbserver1&amp;quot;,
    &amp;quot;table.include.list&amp;quot;: &amp;quot;public.orders&amp;quot;,
    &amp;quot;plugin.name&amp;quot;: &amp;quot;pgoutput&amp;quot;,
    &amp;quot;tasks.max&amp;quot;: &amp;quot;1&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For MongoDB, the setup is pretty similar, but you&amp;#39;d use the MongoDbConnector class and provide the connection details for your MongoDB setup.&lt;/p&gt;
&lt;p&gt;Using Debezium in your DevOps workflow lets you build more event-driven systems. Data gets integrated and synced across your applications in real time. This can make your apps more responsive and your data flow much more efficient.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Running into Walls with Database DevOps? Here&amp;#39;s How to Get Over Them.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Putting Database DevOps into practice isn&amp;#39;t always a walk in the park. One common issue is getting developers and database admins (DBAs) to really &lt;strong&gt;work together smoothly&lt;/strong&gt;. They often have different priorities and ways of doing things. To fix this, you need to build a culture where teamwork is key and everyone understands and respects each other&amp;#39;s roles. Things like training together, having teams with mixed skills, and setting common goals can really help.&lt;/p&gt;
&lt;p&gt;Another challenge is dealing with the &lt;strong&gt;risks that come with changing databases and their structure&lt;/strong&gt;. Unlike application code, database changes can be tough to undo and can mess with your live data. To handle this, you absolutely need to test everything thoroughly in environments that aren&amp;#39;t production, make sure your schema changes don&amp;#39;t break older versions of your app if you can, and have clear, tested plans for rolling back changes if something goes wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Making sure database deployments are the same across all your environments&lt;/strong&gt; can also be tricky. If things aren&amp;#39;t consistent, you can end up with deployments failing or weird issues popping up. Automation is your best friend here – it ensures the same deployment processes and settings are used everywhere, from development to production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Balancing governance with moving fast&lt;/strong&gt; is another important point. Security rules, compliance, and regulations add layers of complexity to database changes. The goal is to build these controls into your DevOps pipeline in a way that keeps you compliant without slowing down your ability to innovate. Using &amp;quot;policy-as-code&amp;quot; and automating compliance checks can help you find that balance.&lt;/p&gt;
&lt;p&gt;Organizations with &lt;strong&gt;older, legacy systems&lt;/strong&gt; might face extra hurdles when trying to bring them into a Database DevOps workflow. These older systems might not have the flexibility or the right tools for easy automation. Taking things step-by-step, starting with automating simple, repetitive tasks and gradually adding more advanced CI/CD practices, can be a good way to handle this.&lt;/p&gt;
&lt;p&gt;Many teams also realize they just &lt;strong&gt;haven&amp;#39;t automated much of their database work yet&lt;/strong&gt;. Finding those manual, repetitive tasks and slowly automating them is key to really getting the full benefits of Database DevOps. It&amp;#39;s smart to start with the things that will give you the biggest wins and then keep automating more and more.&lt;/p&gt;
&lt;p&gt;Finally, people often worry about &lt;strong&gt;how CI/CD processes might affect database performance&lt;/strong&gt;. Careful planning, testing performance in non-production environments, and using techniques like making schema changes while the database is online or deploying changes in small steps can help ease these worries.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Wrapping Up: Why Database DevOps with CI/CD is a Big Deal.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Database DevOps with CI/CD for PostgreSQL and MongoDB really changes the game for managing database changes in today&amp;#39;s fast-moving software world. By focusing on automating things, working together, and always trying to get better, teams can release features faster, cut down on errors and downtime, make data more secure, and just work more efficiently overall.&lt;/p&gt;
&lt;p&gt;Getting to Database DevOps takes a shift in how teams think and work, plus a willingness to try new tools and practices. But the payoff – a database management process that&amp;#39;s smooth, automated, and collaborative – is huge. It lets teams deliver value to users more quickly and reliably. As software development keeps evolving, embracing Database DevOps is going to be crucial for companies that want to stay competitive and keep innovating.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Your Questions About Database DevOps and CI/CD for PostgreSQL/MongoDB, Answered.&lt;/strong&gt;&lt;/h2&gt;
&lt;Accordion client:load title=&quot;What exactly is Database DevOps?&quot;&gt;&lt;ul&gt;
&lt;li&gt;It&amp;#39;s taking the ideas of DevOps like working together, automating things,
and constantly improving and applying them to how you manage your databases.&lt;/li&gt;
&lt;li&gt;The goal is to integrate database work with application development so
everything moves together smoothly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Why is CI/CD important for databases?&quot;&gt;&lt;ul&gt;
&lt;li&gt;It helps you release things faster and more often.&lt;/li&gt;
&lt;li&gt;Reduces mistakes and errors.&lt;/li&gt;
&lt;li&gt;Gets development and database teams working better together.&lt;/li&gt;
&lt;li&gt;Makes deployments more consistent and reliable.&lt;/li&gt;
&lt;li&gt;Improves productivity for everyone involved.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;What are the main ideas behind Database DevOps?&quot;&gt;&lt;ul&gt;
&lt;li&gt;Treat your database like code (version control, collaboration).&lt;/li&gt;
&lt;li&gt;Automate everything: setup, changes, testing, deployment, rollback.&lt;/li&gt;
&lt;li&gt;Use continuous integration and delivery for database changes.&lt;/li&gt;
&lt;li&gt;Foster collaboration and open communication between teams.&lt;/li&gt;
&lt;li&gt;Monitor and get feedback continuously.&lt;/li&gt;
&lt;li&gt;Build security in from the start (Shift Left Security/DevSecOps).&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How is applying CI/CD to databases different from applying it to applications?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Database changes involve managing schema updates and data migrations, which can be more complex than application code changes.&lt;/li&gt;
&lt;li&gt;You must keep data safe and avoid downtime.&lt;/li&gt;
&lt;li&gt;Schema and data changes are harder to roll back than code changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the key differences between app and database CI/CD?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;App CI/CD is mostly about code changes.&lt;/li&gt;
&lt;li&gt;Database CI/CD is about managing schema and data, with a bigger focus on data accuracy and minimizing downtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Why is continuous delivery for databases harder than for applications?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Databases hold the state of your application, and changes can have major impacts if not handled carefully.&lt;/li&gt;
&lt;li&gt;You need to be precise to keep your data accurate and consistent.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the main technical reasons for the difference between app and database continuous delivery?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Deploying an app often means replacing files.&lt;/li&gt;
&lt;li&gt;Deploying database changes means altering structure and data, which depends on the current state of the database.&lt;/li&gt;
&lt;li&gt;Direct changes to a live database lack the safety net of version control.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some common problems you hit with Database DevOps?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Environments not matching up.&lt;/li&gt;
&lt;li&gt;Adding security and compliance.&lt;/li&gt;
&lt;li&gt;Complicated migrations and rollbacks.&lt;/li&gt;
&lt;li&gt;Picking the right tools.&lt;/li&gt;
&lt;li&gt;Managing database changes in version control.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do you automate PostgreSQL schema migrations in CI/CD?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Use tools like Liquibase or Flyway.&lt;/li&gt;
&lt;li&gt;Integrate them into your CI/CD pipelines (Jenkins, GitLab CI, GitHub Actions).&lt;/li&gt;
&lt;li&gt;Automate migration execution and testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;How do you automate MongoDB migrations in CI/CD?&quot;&gt;&lt;ul&gt;
&lt;li&gt;Use tools like Liquibase (with MongoDB extension), migrate-mongo, or Mongock.&lt;/li&gt;
&lt;li&gt;Store migration scripts in version control.&lt;/li&gt;
&lt;li&gt;Run migrations automatically in your CI/CD pipeline.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do I set up Database CI/CD with PostgreSQL using GitHub?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Use GitHub Actions to automate building, testing, and deploying database changes.&lt;/li&gt;
&lt;li&gt;Integrate tools like Flyway or Liquibase in your workflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does Liquibase work with PostgreSQL and MongoDB in CI/CD?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Define your database changes in Liquibase changelog files.&lt;/li&gt;
&lt;li&gt;Use your CI/CD pipeline to run Liquibase commands and apply changes automatically.&lt;/li&gt;
&lt;li&gt;For MongoDB, use the MongoDB extension and define changes in JSON or XML changelogs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do I handle data transformations when the schema evolves?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Include logic in migration scripts to update existing data to fit the new schema.&lt;/li&gt;
&lt;li&gt;This may involve renaming fields, changing data types, or restructuring documents.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can I make sure deployments with schema changes don&amp;#39;t cause downtime?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Make backward-compatible changes when possible.&lt;/li&gt;
&lt;li&gt;Use tools like pgroll for zero-downtime migrations.&lt;/li&gt;
&lt;li&gt;Consider blue/green deployments or rolling updates.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the biggest challenges in implementing Database DevOps?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Getting developers and DBAs to work together.&lt;/li&gt;
&lt;li&gt;Handling risks of data and schema changes.&lt;/li&gt;
&lt;li&gt;Ensuring consistent deployments across environments.&lt;/li&gt;
&lt;li&gt;Managing governance and compliance without slowing down delivery.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;What are the benefits of CI/CD for databases?&quot;&gt;&lt;ul&gt;
&lt;li&gt;Speeds up your development workflow.&lt;/li&gt;
&lt;li&gt;Uses existing CI/CD practices for database changes.&lt;/li&gt;
&lt;li&gt;Quality checks are built-in.&lt;/li&gt;
&lt;li&gt;Database changes flow better and are more reliable.&lt;/li&gt;
&lt;li&gt;Deployments are predictable and environments are consistent.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Database DevOps: What It Is and Why It Matters - Redgate, accessed on May 16, 2025, &lt;a href=&quot;https://www.red-gate.com/solutions/database-devops/&quot;&gt;https://www.red-gate.com/solutions/database-devops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CI/CD for Databases: Best Practices and Tools - Liquibase, accessed on May 16, 2025, &lt;a href=&quot;https://www.liquibase.com/resources/articles/database-cicd-best-practices&quot;&gt;https://www.liquibase.com/resources/articles/database-cicd-best-practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Automate Database Deployments with CI/CD - Flyway, accessed on May 16, 2025, &lt;a href=&quot;https://flywaydb.org/documentation/learnmore/cicd&quot;&gt;https://flywaydb.org/documentation/learnmore/cicd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DevOps for Databases: PostgreSQL and MongoDB - Percona, accessed on May 16, 2025, &lt;a href=&quot;https://www.percona.com/blog/devops-for-databases-postgresql-and-mongodb/&quot;&gt;https://www.percona.com/blog/devops-for-databases-postgresql-and-mongodb/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CI/CD for MongoDB: Best Practices - MongoDB, accessed on May 16, 2025, &lt;a href=&quot;https://www.mongodb.com/developer/products/atlas/cicd-best-practices/&quot;&gt;https://www.mongodb.com/developer/products/atlas/cicd-best-practices/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Database Migrations with migrate-mongo, accessed on May 16, 2025, &lt;a href=&quot;https://github.com/seppevs/migrate-mongo&quot;&gt;https://github.com/seppevs/migrate-mongo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mongock: MongoDB Java Migrations, accessed on May 16, 2025, &lt;a href=&quot;https://mongock.io/&quot;&gt;https://mongock.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Debezium Documentation, accessed on May 16, 2025, &lt;a href=&quot;https://debezium.io/documentation/&quot;&gt;https://debezium.io/documentation/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Change Data Capture with Debezium and Kafka - Confluent, accessed on May 16, 2025, &lt;a href=&quot;https://www.confluent.io/blog/change-data-capture-debezium/&quot;&gt;https://www.confluent.io/blog/change-data-capture-debezium/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Best Practices for Database DevOps - Microsoft DevBlogs, accessed on May 16, 2025, &lt;a href=&quot;https://devblogs.microsoft.com/devops/best-practices-for-database-devops/&quot;&gt;https://devblogs.microsoft.com/devops/best-practices-for-database-devops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CI/CD for Databases: Challenges and Solutions - DZone, accessed on May 16, 2025, &lt;a href=&quot;https://dzone.com/articles/cicd-for-databases-challenges-and-solutions&quot;&gt;https://dzone.com/articles/cicd-for-databases-challenges-and-solutions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL: Frequently Asked Questions, accessed on May 16, 2025, &lt;a href=&quot;https://wiki.postgresql.org/wiki/FAQ&quot;&gt;https://wiki.postgresql.org/wiki/FAQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MongoDB: Frequently Asked Questions, accessed on May 16, 2025, &lt;a href=&quot;https://www.mongodb.com/docs/manual/faq/&quot;&gt;https://www.mongodb.com/docs/manual/faq/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DevOps Database Automation: Why and How - DBmaestro, accessed on May 16, 2025, &lt;a href=&quot;https://www.dbmaestro.com/blog/devops-database-automation-why-and-how&quot;&gt;https://www.dbmaestro.com/blog/devops-database-automation-why-and-how&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Automating Database Deployments with GitHub Actions - Liquibase, accessed on May 16, 2025, &lt;a href=&quot;https://www.liquibase.com/blog/automating-database-deployments-with-github-actions&quot;&gt;https://www.liquibase.com/blog/automating-database-deployments-with-github-actions&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Database DevOps</category><category>CI/CD</category><category>PostgreSQL</category><category>MongoDB</category><category>Automation</category><category>DevOps</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0086-database-devops-ci-cd-postgresql-mongodb/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Microsoft’s Prompt Orchestration Markup Language (POML): Structuring the Future of AI Interaction</title><link>https://mkabumattar.com/blog/post/microsoft-poml-orchestrating-ai-prompts-for-llms/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/microsoft-poml-orchestrating-ai-prompts-for-llms/</guid><description>Ready to ditch manual database updates? Learn how Database DevOps and CI/CD can transform PostgreSQL and MongoDB management for faster, more reliable releases.</description><pubDate>Wed, 20 Aug 2025 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction: What is Microsoft&amp;#39;s POML and Why Does it Matter for AI?&lt;/h2&gt;
&lt;p&gt;Large Language Models, or LLMs, are changing fast, and they&amp;#39;re becoming super important for all sorts of complex applications. Usually, writing good prompts for LLMs what we call prompt engineering has felt more like an art than a science. That&amp;#39;s because we&amp;#39;ve mostly relied on just writing free-form text. While that&amp;#39;s fine for simple chats, it gets really tricky when developers try to build complex AI apps. When prompts get bigger and more complicated, they often turn into what developers call &amp;quot;spaghetti code&amp;quot; it&amp;#39;s messy, hard to fix, and tough to grow. Think about building a huge software system with just plain text files, no programming languages or fancy tools. That&amp;#39;s exactly the kind of problem Microsoft&amp;#39;s Prompt Orchestration Markup Language, or POML, wants to solve for prompt development.&lt;/p&gt;
&lt;p&gt;This change in how we build prompts is a lot like how software engineering itself grew up. Software used to be low-level and messy, but it got better with high-level languages and smart development tools (IDEs). We learned to make things modular, reusable, and easy to track changes. POML isn&amp;#39;t just another tool; it&amp;#39;s a big step toward bringing those proven software engineering ideas into prompt engineering. This profound change could even mean new jobs, like &amp;quot;Prompt Orchestrator&amp;quot; or &amp;quot;AI Architect.&amp;quot; These folks would design the whole brain of AI systems using structured languages like POML, instead of just writing one-off prompts.&lt;/p&gt;
&lt;p&gt;So, what is POML? It&amp;#39;s a new markup language from Microsoft, kind of like HTML for websites, but built specifically to make advanced prompt engineering for LLMs more organized, easier to keep up with, and super flexible. It works as a declarative language, meaning you tell an AI orchestrator&lt;/p&gt;
&lt;p&gt;&lt;em&gt;what&lt;/em&gt; to do like how to run prompts, make choices, call APIs, and handle complicated tasks.&lt;/p&gt;
&lt;p&gt;POML tackles some big problems we&amp;#39;ve seen with traditional prompt development head-on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lack of Structure:&lt;/strong&gt; Regular prompts are often just free-form text, which makes them tough to manage and grow. POML brings in a clear structure, and Microsoft&amp;#39;s own tests show it can cut down on version control headaches by a huge 65%.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex Data Integration:&lt;/strong&gt; Dealing with different kinds of data, like mixing text with images or documents, usually means a lot of manual, clunky work. POML introduces special tags (like &lt;code&gt;&amp;lt;document&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;) that let you easily include or link to outside data. This makes your prompts rich with context and information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Format Sensitivity:&lt;/strong&gt; Even tiny changes in formatting can really mess with what an LLM puts out, making things unpredictable. POML has a styling system, a bit like CSS, that fixes this by keeping your prompt&amp;#39;s content separate from how it looks. This means you can change things like how chatty or formal the AI should be without touching the main instructions. It really helps with that &amp;quot;format sensitivity&amp;quot; LLMs can have. That whole &amp;quot;format sensitivity&amp;quot; thing means LLMs, even with all their smarts, can be surprisingly finicky if you change the input just a little. POML&amp;#39;s clever styling system directly addresses this by separating how your prompt looks from what it actually says. This design isn&amp;#39;t just about making things easier for developers; it&amp;#39;s a smart way to create a layer that helps LLMs behave more reliably and predictably. By handling all those little details of LLM input formatting, POML aims to cut down on &amp;quot;LLM output instability&amp;quot; making your AI apps much more dependable. This focus on making things robust shows that POML could help LLM applications move from being cool experiments to solid, production-ready systems where consistent results and less debugging are super important.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inadequate Tooling and Collaboration Challenges:&lt;/strong&gt; Without standard ways to write prompts and good tools, working together on prompts is a nightmare. POML gives you a consistent way to write things and a great set of development tools, including a VS Code extension and SDKs. Early users say it&amp;#39;s boosted their team&amp;#39;s productivity by 30%.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How Does POML Bring Structure to Prompt Engineering?&lt;/h2&gt;
&lt;p&gt;POML really changes prompt engineering by making it structured and modular, so creating prompts feels a lot more like regular software development.&lt;/p&gt;
&lt;h3&gt;Semantic Markup: Building Blocks for Clearer Prompts&lt;/h3&gt;
&lt;p&gt;POML uses a simple, HTML-like way of writing things, with meaningful components that help you build prompts in a modular way. This makes them much easier to read, reuse, and keep updated. These structured tags help developers take big, complicated prompts and break them into smaller, organized, and easier-to-handle pieces. When you see tags like&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;role&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;task&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;example&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;output-format&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;hint&amp;gt;&lt;/code&gt; in POML, it tells you this isn&amp;#39;t just any markup language. It means Microsoft is actually putting common prompt engineering &amp;quot;patterns&amp;quot; like telling the AI what role to play, giving it clear tasks, showing it examples, setting output rules, or giving it little nudges into a formal, structured language. This smart move turns prompt engineering from a random, experimental process into something much more standardized, repeatable, and scalable. It also hints that they understand how LLMs react to structured input, even if the models weren&amp;#39;t specifically trained on POML itself. This standardization could really speed up how we develop and use the best practices in prompt engineering. It&amp;#39;ll make it much simpler for new developers to jump in and help with big AI projects, ultimately building a more mature development world.&lt;/p&gt;
&lt;p&gt;Here are some of the main semantic tags you&amp;#39;ll find in POML:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;role&amp;gt;&lt;/code&gt;:&lt;/strong&gt; This component defines the persona or specific role the LLM should adopt for a given task. For example, a prompt might begin with &lt;code&gt;&amp;lt;role&amp;gt;You are a patient teacher explaining concepts to a 10-year-old.&amp;lt;/role&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;task&amp;gt;&lt;/code&gt;:&lt;/strong&gt; This tag outlines the specific instruction or objective that the LLM needs to perform. An example could be &lt;code&gt;&amp;lt;task&amp;gt;Explain the concept of photosynthesis using the provided image as a reference.&amp;lt;/task&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;example&amp;gt;&lt;/code&gt;:&lt;/strong&gt; Crucial for few-shot prompting, this component provides concrete examples to guide the LLM&amp;#39;s understanding and response generation. It often includes nested &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;output&amp;gt;&lt;/code&gt; subcomponents to clearly delineate the example&amp;#39;s structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;output-format&amp;gt;&lt;/code&gt;:&lt;/strong&gt; This tag dictates the desired format and stylistic constraints for the LLM&amp;#39;s response. For instance, it could specify &lt;code&gt;&amp;lt;output-format&amp;gt;Keep the explanation simple, engaging, and under 100 words. Start with &amp;quot;Hey there, future scientist!&amp;quot;.&amp;lt;/output-format&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;document&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;:&lt;/strong&gt; These are specialized data components designed for seamlessly embedding or referencing external data sources directly within the prompt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;hint&amp;gt;&lt;/code&gt;:&lt;/strong&gt; This tag adds contextual guidance or subtle suggestions to assist the LLM in its response generation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;qa&amp;gt;&lt;/code&gt;:&lt;/strong&gt; A specific tag introduced to cleanly separate a customer&amp;#39;s question from the desired response, effectively turning prompts into support agents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;let&amp;gt;&lt;/code&gt;:&lt;/strong&gt; This tag is used to define variables within the POML structure, enabling dynamic content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;stylesheet&amp;gt;&lt;/code&gt;:&lt;/strong&gt; This component allows developers to define global or scoped styles for elements, similar to CSS.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Key POML Semantic Tags and Their Functions&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;&lt;strong&gt;Tag&lt;/strong&gt;&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;&lt;strong&gt;Example Use Case&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;role&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Defines the LLM&amp;#39;s persona or role.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;role&amp;gt;You are a witty science communicator.&amp;lt;/role&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;task&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Outlines the specific instruction or objective.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;task&amp;gt;Describe how a rocket launches.&amp;lt;/task&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;example&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Provides few-shot examples for guidance.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;example&amp;gt;&amp;lt;input&amp;gt;What is 2+2?&amp;lt;/input&amp;gt;&amp;lt;output&amp;gt;4&amp;lt;/output&amp;gt;&amp;lt;/example&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Embeds or references images for context.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;img src=&amp;quot;diagram.png&amp;quot; alt=&amp;quot;Process diagram&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;document&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Embeds or references external text documents.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;document src=&amp;quot;report.pdf&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Embeds or references tabular data.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;table&amp;gt; src=&amp;quot;sales.csv&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;stylesheet&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Defines global or scoped presentation styles.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;stylesheet&amp;gt;{ &amp;quot;p&amp;quot;: { &amp;quot;syntax&amp;quot;: &amp;quot;json&amp;quot; } }&amp;lt;/stylesheet&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;let&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Defines variables for dynamic content.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;let name=&amp;quot;user_name&amp;quot;&amp;gt;Alice&amp;lt;/let&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;if (attribute)&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Applies conditional logic to elements.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;p if=&amp;quot;is_admin&amp;quot;&amp;gt;Admin message.&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;for (attribute)&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Iterates over lists to generate dynamic content.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;item for=&amp;quot;item in list&amp;quot;&amp;gt;{{item}}&amp;lt;/item&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;hint&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Adds contextual guidance for the LLM.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;hint&amp;gt;Focus on the key takeaways.&amp;lt;/hint&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;qa&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Separates a question from its desired response.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;qa&amp;gt;&amp;lt;question&amp;gt;What is POML?&amp;lt;/question&amp;gt;&amp;lt;answer&amp;gt;...&amp;lt;/answer&amp;gt;&amp;lt;/qa&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;output-format&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Specifies the desired format/style of LLM output.&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;&amp;lt;output-format style=&amp;quot;verbose&amp;quot;&amp;gt;Provide a detailed explanation.&amp;lt;/output-format&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Comprehensive Data Handling: Beyond Just Text&lt;/h3&gt;
&lt;p&gt;POML lets you easily bring all sorts of data right into your prompts, going way beyond just static text. You can embed or link to outside data like text files, spreadsheets, images, Word documents, PDFs, CSVs, and even audio files. This makes your prompts incredibly dynamic and full of context, so they can look more like detailed reports than just simple sentences.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example that shows how you can include an image for context&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;poml&amp;gt;
  &amp;lt;role&amp;gt;You are a patient teacher explaining concepts to a 10-year-old.&amp;lt;/role&amp;gt;
  &amp;lt;task&amp;gt;Explain the concept of photosynthesis using the provided image as a reference.&amp;lt;/task&amp;gt;
  &amp;lt;img src=&amp;quot;photosynthesis_diagram.png&amp;quot; alt=&amp;quot;Diagram of photosynthesis&amp;quot; /&amp;gt;
  &amp;lt;output-format&amp;gt; Keep the explanation simple, engaging, and under 100 words. Start with &amp;quot;Hey there, future scientist!&amp;quot;. &amp;lt;/output-format&amp;gt;
&amp;lt;/poml&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example clearly shows how you can embed an image to give the AI visual context, highlighting POML&amp;#39;s strong support for multimodal prompts and its ability to enrich LLM interactions with different kinds of media.&lt;/p&gt;
&lt;h3&gt;Decoupled Presentation Styling: Content Meets Style&lt;/h3&gt;
&lt;p&gt;Taking a cue from CSS, POML has a powerful styling system that completely separates what your prompt says from how it looks. This separation means you can change things like how chatty, formal, or structured the AI&amp;#39;s response should be, using&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;stylesheet&amp;gt;&lt;/code&gt; definitions or inline attributes, without touching the main instructions of your prompt. This decoupling is super important for dealing with LLM format sensitivity, and it makes A/B testing different ways of presenting your prompts much easier, helping you get the best results from your LLMs. For example, you could make all captions appear in uppercase just by setting a style rule.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a snippet illustrating this capability&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;poml&amp;gt;
  &amp;lt;output-format style=&amp;quot;verbose&amp;quot;&amp;gt; Please provide a detailed, step-by-step explanation suitable for adults. &amp;lt;/output-format&amp;gt;
&amp;lt;/poml&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This snippet shows how a straightforward &lt;code&gt;style&lt;/code&gt; attribute can instantly change the expected output&amp;#39;s verbosity and detail level, all without needing any changes to the core instructional content of the prompt.&lt;/p&gt;
&lt;h3&gt;Integrated Templating Engine: Dynamic Prompt Generation&lt;/h3&gt;
&lt;p&gt;POML comes with a powerful, built-in templating engine that supports variables (&lt;code&gt;{{ }}&lt;/code&gt;), loops (&lt;code&gt;for&lt;/code&gt;), conditionals (&lt;code&gt;if&lt;/code&gt;), and defining variables (&lt;code&gt;&amp;lt;let&amp;gt;&lt;/code&gt;). This dynamic system lets you programmatically create complex, data-driven prompts. You can do cool things like tailoring responses based on a user&amp;#39;s permissions or looping through large datasets. This advanced templating really brings prompt engineering much closer to what we do in traditional software programming.&lt;/p&gt;
&lt;p&gt;This compelling snippet demonstrates the power of POML&amp;#39;s templating engine&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;poml&amp;gt;
  &amp;lt;let name=&amp;quot;all_demos&amp;quot; value=&amp;#39;&amp;#39;/&amp;gt;
  &amp;lt;examples&amp;gt;
    &amp;lt;example for=&amp;quot;example in all_demos&amp;quot; chat=&amp;quot;false&amp;quot; caption=&amp;quot;Example {{ loop.index + 1 }}&amp;quot; captionStyle=&amp;quot;header&amp;quot;&amp;gt;
      &amp;lt;input&amp;gt;{{ example.input }}&amp;lt;/input&amp;gt;
      &amp;lt;output&amp;gt;{{ example.output }}&amp;lt;/output&amp;gt;
    &amp;lt;/example&amp;gt;
  &amp;lt;/examples&amp;gt;
&amp;lt;/poml&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example iterates through a predefined list of examples (&lt;code&gt;all_demos&lt;/code&gt;) and dynamically generates captions like &amp;quot;Example 1&amp;quot; and &amp;quot;Example 2&amp;quot; using &lt;code&gt;loop.index + 1&lt;/code&gt;. This showcases how POML can automate the creation of structured few-shot prompts, ensuring consistency and reducing manual effort.&lt;/p&gt;
&lt;h2&gt;What Development Tools Support POML and Streamline the Workflow?&lt;/h2&gt;
&lt;p&gt;Good development tools are key for any new technology to really take off and be useful. POML has a full set of tools that are designed to make prompt engineering much smoother.&lt;/p&gt;
&lt;h3&gt;Visual Studio Code Extension: An IDE-Like Experience for Prompt Engineering&lt;/h3&gt;
&lt;p&gt;Microsoft&amp;#39;s POML extension for Visual Studio Code is packed with features, and it really makes prompt engineering feel a lot like traditional software development. This is a big deal for getting developers to use it, because it gives them a familiar, efficient, and powerful place to work with prompts. Microsoft&amp;#39;s put a lot of effort into this strong extension and it&amp;#39;s more than just a handy tool. Since so many developers already use VS Code putting POML right into it is a smart move that builds on Microsoft&amp;#39;s existing strengths. This isn&amp;#39;t just about making POML easier to use; it&amp;#39;s a clear effort to &amp;quot;standardize the AI development workflow&amp;quot; and really cement &amp;quot;VS Code, GitHub, and Azure as the go-to ecosystem for building serious AI solutions&amp;quot;. By making everything so connected and integrated, Microsoft is creating an environment that encourages developers to stick with their tools for AI projects. This deep integration of tools really points to Microsoft&amp;#39;s long-term goal: to own and simplify the entire AI development process, from writing the first prompt to deploying and managing it.&lt;/p&gt;
&lt;p&gt;Here are some of the key features you&amp;#39;ll find in the POML Visual Studio Code extension&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Syntax Highlighting:&lt;/strong&gt; It makes different parts of your &lt;code&gt;.poml&lt;/code&gt; files stand out visually, which really helps you read and understand your code better.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context-Aware Auto-completion (IntelliSense):&lt;/strong&gt; It gives you smart suggestions for tags and attributes as you type, which can cut down the time you spend looking up syntax by about 50%.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hover Documentation:&lt;/strong&gt; You can just hover over POML elements to instantly see documentation and info, helping you understand how to use them correctly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time Previews:&lt;/strong&gt; It shows you what your POML prompts will look like as you write them, so you don&amp;#39;t have to keep testing them with a model. This can cut debugging time by an amazing 80%! This feature alone is a huge help for quickly trying out new prompt ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inline Diagnostics for Error Checking:&lt;/strong&gt; It gives you instant feedback on errors right in your code, pointing out syntax problems, missing fields, or type mismatches. This helps you catch about 40% of errors early on, speeding up debugging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrated Interactive Testing:&lt;/strong&gt; You can even test your prompts right inside VS Code, setting up your preferred model providers (like OpenAI, Azure, or Google), API keys, and endpoint URLs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Cross-Platform SDKs: Seamless Integration into Applications&lt;/h3&gt;
&lt;p&gt;To make sure POML works for everyone and fits into different developer worlds, Microsoft has released SDKs for popular languages like Node.js (JavaScript/TypeScript) and Python. These SDKs make it super easy to plug POML prompts into all sorts of applications and existing LLM frameworks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node.js (TypeScript) SDK:&lt;/strong&gt; You can easily install this SDK using &lt;code&gt;npm install pomljs&lt;/code&gt;. It lets developers import POML components (like &lt;code&gt;Paragraph&lt;/code&gt; and &lt;code&gt;Image&lt;/code&gt;), parse POML markup into an intermediate representation (IR), and then turn that IR into various output formats, including Markdown.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// Import necessary components and functions from the POML SDK
import { Paragraph, Image } from &amp;#39;poml/essentials&amp;#39;;
import { read, write } from &amp;#39;poml&amp;#39;;

// Define a POML prompt using JSX-like syntax
const prompt = &amp;lt;Paragraph&amp;gt;
 Hello, world! Here is an image:
 &amp;lt;Image src=&amp;quot;photo.jpg&amp;quot; alt=&amp;quot;A beautiful scenery&amp;quot; /&amp;gt;
&amp;lt;/Paragraph&amp;gt;;

// Parse the prompt components into an intermediate representation (IR)
// This step processes the structured POML into an internal format
const ir = await read(prompt);

// Render the IR to different formats, for example, Markdown
// This converts the internal representation into a human-readable string
const markdown = write(ir);

// You can then use the &amp;#39;markdown&amp;#39; string as input for an LLM or display it
console.log(markdown);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Python SDK:&lt;/strong&gt; Developers can install the Python SDK using &lt;code&gt;pip install --upgrade poml&lt;/code&gt;. This SDK lets you work with POML files and components directly in your Python projects. You can load from files, apply stylesheets, and get outputs in various formats (like OpenAI chat format or Pydantic objects). Plus, it has built-in integrations with popular tools like LangChain, MLflow, and Weave for better logging and templating.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Import the main poml function
from poml import poml

# Basic usage: process a markup string with context
# The &amp;#39;name&amp;#39; variable in the markup will be replaced by &amp;#39;World&amp;#39;
result = poml(&amp;quot;&amp;lt;p&amp;gt;Hello {{name}}!&amp;lt;/p&amp;gt;&amp;quot;, context={&amp;quot;name&amp;quot;: &amp;quot;World&amp;quot;})
print(result) # Expected output: {&amp;#39;content&amp;#39;: &amp;#39;Hello World!&amp;#39;, &amp;#39;format&amp;#39;: &amp;#39;text&amp;#39;}

# Example of loading from a file and applying a stylesheet (assuming chat.poml exists)
# messages = poml(
#     &amp;quot;chat.poml&amp;quot;,
#     stylesheet={&amp;quot;role&amp;quot;: {&amp;quot;captionStyle&amp;quot;: &amp;quot;bold&amp;quot;}}, # Apply a custom style
#     format=&amp;quot;openai_chat&amp;quot; # Get output in OpenAI chat message format
# )
# print(messages) # Expected output: List of OpenAI chat messages
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The POML community is also growing, with projects like &lt;code&gt;mini-poml-rs&lt;/code&gt; (an experimental Rust-based renderer) and &lt;code&gt;poml-ruby&lt;/code&gt; (a Ruby gem implementation). These projects show that there&amp;#39;s wider interest and that POML could be used with even more programming languages and environments.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s pretty interesting, and a bit odd, that even though Microsoft created POML and.NET is a core Microsoft developer platform, the info we have clearly says there&amp;#39;s &amp;quot;no C#/.NET SDK&amp;quot;. The community&amp;#39;s called this &amp;quot;wild&amp;quot; and &amp;quot;Classic Microsoft behavior&amp;quot;. This seems like an oversight or a choice that leaves a big hole in Microsoft&amp;#39;s otherwise complete tool strategy, making.NET developers have to &amp;quot;Frankenstein together something just to use it in my stack&amp;quot;. This missing piece could really slow down how many.NET developers pick up POML, limiting its overall reach and impact, even with all its other great features. It also makes you wonder about how Microsoft is aligning its internal strategy and allocating resources for new open-source projects.&lt;/p&gt;
&lt;h2&gt;What Are the Practical Benefits and &amp;quot;Killer&amp;quot; Use Cases of POML?&lt;/h2&gt;
&lt;p&gt;POML brings real, measurable improvements for developers and companies. It fixes old problems in prompt engineering and opens the door for new kinds of AI applications.&lt;/p&gt;
&lt;h3&gt;Quantifiable Improvements for Developers and Organizations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Higher Efficiency:&lt;/strong&gt; Microsoft&amp;#39;s early internal tests show that developers using POML are over 40% more efficient when they&amp;#39;re building complex prompts. This efficiency comes from POML&amp;#39;s structured approach and strong tools that make creating and managing prompts much simpler.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved Maintainability:&lt;/strong&gt; POML really makes prompts easier to maintain, so developers &amp;quot;won&amp;#39;t lose their mind when prompts get long, messy, and reused by 5 different teams across 3 time zones&amp;quot;. Its modular design and clear structure make prompts simpler to understand, update, and manage as time goes on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced Collaboration:&lt;/strong&gt; Because it gives you a unified and structured way to write prompts, POML has reportedly boosted team productivity by 30% for early users, making collaborative prompt development much smoother. This standardization means less confusion and easier teamwork.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced Version Control Conflicts:&lt;/strong&gt; POML&amp;#39;s structured approach led to an amazing 65% drop in version control conflicts during Microsoft&amp;#39;s internal tests. That&amp;#39;s a huge plus for teams sharing prompt code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster Debugging:&lt;/strong&gt; The Visual Studio Code extension&amp;#39;s real-time preview shows you your prompts instantly, cutting debugging time by a massive 80%. This instant visual feedback helps developers find and fix problems super fast.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Early Error Detection:&lt;/strong&gt; The VS Code extension&amp;#39;s error diagnostics give you immediate feedback, helping you catch about 40% of early syntax issues, missing fields, or type mismatches. Catching errors this early saves a ton of time and effort later on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplified Dynamic Prompt Generation:&lt;/strong&gt; POML&amp;#39;s built-in templating engine makes creating dynamic prompts a breeze, like tailoring responses based on user permissions or real-time data. This flexibility is key for building AI systems that can adapt.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Real-World Applications (&amp;quot;Killer Use Cases&amp;quot;)&lt;/h3&gt;
&lt;p&gt;The really cool &amp;quot;killer use cases&amp;quot; show that POML is useful for much more than just writing individual prompts. It&amp;#39;s built to help you create complete, strong AI-powered applications. Automating complex reports, doing systematic A/B testing to make things better, and generating instructions with different types of media these are all application-level features, not just single prompt tasks. This strongly suggests that POML&amp;#39;s real value is in helping you build scalable and maintainable AI solutions, effectively closing the gap between just talking to an LLM and doing full-on software engineering. This makes POML a crucial part of the foundation for building serious AI systems for businesses, making advanced AI easier to get into and manage for regular software development teams. That&amp;#39;ll speed up AI adoption everywhere.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Content Generation (Automating Reports):&lt;/strong&gt; POML is fantastic for areas that need structured reports, like finance or operations. One e-commerce company managed to automate their weekly sales reports, turning a two-day manual job into just 15 minutes. Their POML templates smoothly combined database queries with natural language, giving them consistent, real-time analysis.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A/B Testing for Prompt Optimization:&lt;/strong&gt; POML&amp;#39;s separated styling system makes it much easier to systematically A/B test different versions of your prompts. Duolingo, for instance, said they found optimal prompts 75% faster and increased their test coverage threefold, which directly made users happier. This capability is vital for constantly making LLM performance better in live systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multimodal Instruction Generation:&lt;/strong&gt; For apps that mix text with different kinds of media, like creating product descriptions with pictures, POML&amp;#39;s &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag lets you integrate them smoothly. A furniture retailer used this feature to automatically create image captions with a consistent style and structure. Plus, POML supports embedding other file types like PDFs, CSVs, and audio files, making your prompts incredibly rich with data and super versatile.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How Does POML Fit into Multi-Agent AI Workflows?&lt;/h2&gt;
&lt;p&gt;As AI tasks get more complicated, we&amp;#39;re seeing more multi-agent systems pop up. That&amp;#39;s where several specialized AI agents work together to hit a common goal.&lt;/p&gt;
&lt;h3&gt;The Growing Complexity of Multi-Agent Systems&lt;/h3&gt;
&lt;p&gt;Regular single-agent systems just can&amp;#39;t handle really complex, multi-part tasks on their own. Getting multiple specialized AI agents, each with their own skills or roles, to work together lets us build more robust, adaptable systems that can solve problems collaboratively. This way of building things is especially good for tasks that need a lot of parallel work, handling information too big for one model&amp;#39;s memory, and connecting with many complex tools.&lt;/p&gt;
&lt;p&gt;While multi-agent systems are super powerful and flexible, they&amp;#39;re known to &amp;quot;burn through tokens fast&amp;quot; usually using about 15 times more tokens than a simple chat. That means higher running costs. POML&amp;#39;s structured approach, which is built for efficiency and maintainability can really help by making prompts shorter and cutting out extra info. By giving subagents clear tasks and structured inputs POML can help agents run more efficiently, which can lower some of those higher token costs. This makes multi-agent systems more affordable, especially for high-value tasks where the better performance is worth the cost. POML could become a key tool for making complex AI systems financially practical, making sure the extra value you get from smart multi-agent teamwork is worth the higher computing costs.&lt;/p&gt;
&lt;h3&gt;POML&amp;#39;s Role in Structuring and Orchestrating Prompts for Collaborative AI Agents&lt;/h3&gt;
&lt;p&gt;POML is clearly &amp;quot;built for multi-agent systems&amp;quot;. It gives you a structured and organized way to define how different parts like language models, outside functions, and memory systems talk to each other and work together in a prompt-driven process. This lets developers build AI systems that are scalable, modular, and easy to maintain, going way beyond simple, one-off conversations. It enables dynamic, multi-step thinking across many agents.&lt;/p&gt;
&lt;p&gt;While Semantic Kernel offers a strong framework for agent orchestration and some sources say Semantic Kernel&amp;#39;s documentation doesn&amp;#39;t directly mention POML&amp;#39;s integration other sources clearly state that &amp;quot;Microsoft debuts POML a new open-source language for orchestrating AI prompts across multi-agent systems&amp;quot;. This means POML &amp;quot;simplifies how developers design and coordinate AI prompts&amp;quot; and &amp;quot;makes AI workflows more structured, scalable, and adaptable,&amp;quot; especially for multi-agent systems. This suggests that POML provides the really important structured prompt definitions needed for agents in a multi-agent system to talk, delegate, and assign tasks effectively. It gives you a standard way to define the &amp;quot;objectives, output formats, guidance on tools and sources&amp;quot; for subagents, which is super important for avoiding duplicate work and keeping tasks clear. POML basically acts as the &amp;quot;instruction set&amp;quot; for autonomous agents making it a core part of building the next wave of complex, collaborative AI systems, even if its direct integration with frameworks like Semantic Kernel isn&amp;#39;t fully detailed everywhere yet.&lt;/p&gt;
&lt;p&gt;The &amp;quot;view layer&amp;quot; idea built into POML&amp;#39;s architecture is really helpful here, because it makes debugging prompts super smooth, especially when you&amp;#39;re dealing with complex multi-prompt agent workflows. While the articles we looked at don&amp;#39;t show direct examples of POML and Semantic Kernel working together Semantic Kernel is a lightweight SDK specifically designed to help developers integrate LLMs, orchestrate multiple AI agents, manage complex workflows, and create structured interactions between people and AI. POML&amp;#39;s natural ability to provide structured, maintainable, and templated prompts fits perfectly with Semantic Kernel&amp;#39;s main goal of building strong multi-agent systems. Semantic Kernel supports different ways of orchestrating agents like Concurrent, Sequential, Handoff, and Group Chat all of them would really benefit from the precise and flexible prompts that POML helps create.&lt;/p&gt;
&lt;h2&gt;What Are the Technical Underpinnings of POML?&lt;/h2&gt;
&lt;p&gt;If you understand how POML is built, you&amp;#39;ll see how it manages to bring structure, maintainability, and versatility to prompt engineering.&lt;/p&gt;
&lt;h3&gt;The &amp;quot;View Layer&amp;quot; Concept: Prompt as Presentation&lt;/h3&gt;
&lt;p&gt;POML&amp;#39;s design is really based on the &amp;quot;view layer&amp;quot; idea, much like the Model-View-Controller (MVC) architecture you see in traditional frontend development. In this setup, POML clearly defines how the prompt looks, keeping it separate from the actual data and the logic behind it. This separation lets developers focus on how information appears and is styled in the prompt, without having to worry about complicated data integration or tricky formatting details. Someone from Microsoft Research, who helped build POML, explained this vision. They said POML was designed so that &amp;quot;the view layer should take care of the data, the styles and rendering logic, so that the user no longer needs to care how some table needs to be rendered, how to present few-shot examples, how to reformat the whole prompt with another syntax (e.g., from markdown to XML)&amp;quot;.&lt;/p&gt;
&lt;h3&gt;The Compilation Process: From Markup to Plain Text&lt;/h3&gt;
&lt;p&gt;At its heart, POML is a markup language, using tags just like HTML. Developers write their prompts in POML, and then the POML SDK does something really important: it &amp;quot;compiles it into a plain-text prompt&amp;quot; before that flattened output goes to the LLM. You can think of this as turning a structured blueprint into a flat, easy-to-read document that the LLM can directly use.&lt;/p&gt;
&lt;p&gt;The full POML architecture uses a clever three-step process for rendering, which makes sure it&amp;#39;s flexible and can handle mixed content really well&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Segmentation Pass:&lt;/strong&gt; First, it scans the raw file content and breaks it down into a hierarchical tree of segments. Each piece gets classified as either &lt;code&gt;META&lt;/code&gt; (for things like settings), &lt;code&gt;POML&lt;/code&gt; (for markup blocks), or &lt;code&gt;TEXT&lt;/code&gt; (for plain text). This step mainly finds where the POML blocks start and end, without fully digging into their complex XML structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metadata Processing:&lt;/strong&gt; Next, all the &lt;code&gt;META&lt;/code&gt; segments it found are processed to fill up a global &lt;code&gt;PomlContext&lt;/code&gt; object, which holds variables and other important context. Once they&amp;#39;re processed, these segments are removed from the tree, since their only job is to set up the context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text/POML Dispatching (Recursive Rendering):&lt;/strong&gt; This last, crucial step involves sending &lt;code&gt;TEXT&lt;/code&gt; and &lt;code&gt;POML&lt;/code&gt; segments to their specific readers for rendering. The PureTextReader takes care of &lt;code&gt;TEXT&lt;/code&gt; segments, rendering their content (maybe using a Markdown processor) and swapping in any variables. The PomlReader handles &lt;code&gt;POML&lt;/code&gt; segments. Before parsing the XML, it replaces any direct child &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt; regions with placeholder tags that close themselves (like &lt;code&gt;&amp;lt;text ref=&amp;#39;TEXT_ID_123&amp;#39; /&amp;gt;&lt;/code&gt;). The original content of these &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt; segments gets stored separately in &lt;code&gt;context.texts&lt;/code&gt;. This clever trick makes sure the XML parser inside &lt;code&gt;PomlFile&lt;/code&gt; doesn&amp;#39;t run into non-XML content and crash. In the end, it creates the final, flattened prompt for the LLM.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The way POML gets compiled from its structured form into a plain-text prompt is a really important design choice with big implications. This means the LLM itself doesn&amp;#39;t need to &amp;quot;understand&amp;quot; or interpret POML&amp;#39;s specific tags or how it&amp;#39;s structured. Instead, it just gets a standard, flat text prompt. This intentional design makes POML work with&lt;/p&gt;
&lt;p&gt;&lt;em&gt;any&lt;/em&gt; LLM, no matter if that model was specifically trained on POML syntax or not. This directly answers the common criticism from the community that &amp;quot;LLMs don’t care about formatting unless they were trained to&amp;quot;. So, POML&amp;#39;s real value is in structuring and making the&lt;/p&gt;
&lt;p&gt;&lt;em&gt;input generation process&lt;/em&gt; smoother for developers, rather than changing how the LLM actually processes text. This makes POML much more widely applicable, positioning it as a versatile tool that works with different LLM providers and models, instead of being stuck in just one Microsoft-trained ecosystem.&lt;/p&gt;
&lt;h3&gt;The Role of Intermediate Representation (IR)&lt;/h3&gt;
&lt;p&gt;While we don&amp;#39;t have all the nitty-gritty details about POML&amp;#39;s Intermediate Representation (IR), the idea of an IR is super important in how compilers work and how programs are analyzed. An IR is like an internal blueprint that represents source code in a way that&amp;#39;s perfect for more processing, optimization, and translation. For POML, after the initial segmentation and parsing, the structured POML content is very likely turned into this kind of IR. This intermediate form would allow for internal logic like templating, swapping out variables, and conditional rendering, all before it&amp;#39;s finally &amp;quot;flattened&amp;quot; into a plain-text prompt for the LLM. The Node.js SDK example actually mentions parsing &amp;quot;prompt components into an intermediate representation (IR)&amp;quot; and then rendering it which confirms that an IR is a key part of how POML processes things.&lt;/p&gt;
&lt;p&gt;The fact that they explicitly mention an Intermediate Representation (IR) and that detailed multi-pass processing pipeline really drives home the idea that POML is like a sophisticated &amp;quot;compiler&amp;quot; for prompts. Just like a regular compiler turns high-level code into optimized machine code using an IR for better performance and portability POML takes structured, human-readable markup and turns it into an optimized, flat text prompt that LLMs can use. This advanced behind-the-scenes processing is exactly what makes POML&amp;#39;s cool features like dynamic templating and separated styling work so smoothly and efficiently. This technical depth suggests that POML is way more than just a simple templating engine; it&amp;#39;s a robust and smartly designed system for creating complex prompts, hinting at possible future features like static analysis, advanced debugging, or even prompt optimization at the IR level.&lt;/p&gt;
&lt;h2&gt;What Are the Criticisms and Community Perspectives on POML?&lt;/h2&gt;
&lt;p&gt;When POML first came out, it got all sorts of reactions in the tech community, sparking &amp;quot;intriguingly polarized&amp;quot; discussions on places like Reddit and Hacker News. This mixed reception really shows the ongoing debate between keeping things simple and adding structure in the fast-changing world of AI.&lt;/p&gt;
&lt;p&gt;The main tension in the criticisms especially the idea that LLMs don&amp;#39;t care about formatting versus POML&amp;#39;s intentional structure reveals a core paradox in today&amp;#39;s AI development. LLMs are built to understand natural language, but to get consistent and predictable results in prompt engineering, you often need highly structured, almost programmatic inputs. POML tries to fix this by giving you a human-friendly, structured &lt;em&gt;writing&lt;/em&gt; experience, which then gets &amp;quot;flattened&amp;quot; into a plain-text prompt for the LLM. This ongoing debate highlights the constant challenge of designing good interfaces that connect precise human intent (managed and structured by POML) with the nuanced, often less predictable, ways LLMs process things (since they work with natural language). POML&amp;#39;s ultimate success depends on whether its &amp;quot;flattened&amp;quot; output is truly best for LLMs, and more importantly, if the real benefits it gives developers are worth the perceived extra work or complexity. This lively debate shows how prompt engineering is growing up as a field. As the field moves forward, tools like POML will keep getting a close look to see their practical value, efficiency, and overall impact on building real-world AI applications, pushing the limits of how we interact with and control advanced AI.&lt;/p&gt;
&lt;p&gt;Here are some of the main criticisms and concerns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LLMs&amp;#39; Understanding of Formatting:&lt;/strong&gt; A big, repeated criticism is the claim that &amp;quot;LLMs don’t care about formatting unless they were trained to&amp;quot;. Critics say that if an LLM hasn&amp;#39;t been specifically trained to understand and use POML tags, it might just ignore them or, even worse, &amp;quot;choke on them,&amp;quot; leading to unpredictable or bad results. This means POML&amp;#39;s effectiveness might really depend on how LLMs are trained in the future, or if it can consistently turn into a format that all LLMs can reliably understand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Added Layer of Abstraction:&lt;/strong&gt; Some people feel POML adds an &amp;quot;unnecessary layer of abstraction&amp;quot;. They argue that it turns a simple &amp;quot;text → LLM&amp;quot; interaction into a more complex &amp;quot;text → markup → compile → LLM&amp;quot; pipeline, adding &amp;quot;More moving parts. More failure points,&amp;quot; which can make debugging and managing the whole system harder. Even a Microsoft Research team member admitted to feeling &amp;quot;hopeless about POML&amp;quot; at one point, recognizing that models have evolved so quickly they&amp;#39;re less sensitive to small format changes now.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Heavy&amp;quot; and Verbose Syntax:&lt;/strong&gt; POML&amp;#39;s syntax has been called &amp;quot;heavy&amp;quot; and like &amp;quot;2005-era websites again,&amp;quot; with &amp;quot;Verbose tags&amp;quot; and &amp;quot;Bracket soup&amp;quot;. This criticism suggests that even though it aims to add structure, the syntax might not always be the easiest or prettiest for developers to read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lack of.NET Support:&lt;/strong&gt; A particularly hot topic, especially since Microsoft is behind POML, is the obvious lack of a C#/.NET SDK. Some see this as &amp;quot;wild&amp;quot; and &amp;quot;Classic&amp;quot; Microsoft behavior,&amp;quot; forcing.NET developers to &amp;quot;Frankenstein together something just to use it in my stack&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Structure for Developers, Not LLMs Directly:&lt;/strong&gt; A common feeling is that POML mainly offers &amp;quot;structure for devs who are writing prompts in messy workflows,&amp;quot; rather than directly making the LLM smarter. While it definitely helps human developers manage long, complex, and reused prompts, its direct effect on the LLM&amp;#39;s performance or how it understands things is questioned, especially if the model isn&amp;#39;t specifically trained on this format. Critics suggest it might just be &amp;quot;wrapping clean text with noisy tags&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Programming LLMs to Program&amp;quot;:&lt;/strong&gt; This higher-level criticism points out the growing layers of abstraction: &amp;quot;The tool that writes prompts is now a program, which builds programs, which generate code&amp;quot;. This view suggests an approach that might be too complicated for what you&amp;#39;re trying to do, raising questions about finding the right balance between abstraction and direct control.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion: The Future of Prompt Engineering with POML&lt;/h2&gt;
&lt;p&gt;POML introduces much-needed structure, scalability, and maintainability to the intricate field of prompt engineering. Its modular syntax, comprehensive data handling capabilities, decoupled styling, dynamic templating engine, and rich integration ecosystem collectively position it as a highly promising standard for orchestrating advanced LLM applications. It is actively transforming prompt engineering from an &amp;quot;art form&amp;quot; into a &amp;quot;professional, scalable discipline,&amp;quot; capable of meeting the demands of enterprise-grade AI solutions. Whether the task involves building complex multi-agent workflows, debugging intricate prompt logic, or developing reusable AI modules for production environments, POML offers a powerful and innovative new foundation for developers.&lt;/p&gt;
&lt;p&gt;POML represents Microsoft&amp;#39;s strategic answer to bringing order and scalability to prompt engineering, much in the same way that HTML revolutionized web development by introducing structure. By making POML an open-source project , Microsoft aims to standardize the entire AI development workflow, thereby solidifying Visual Studio Code, GitHub, and Azure as the preferred, comprehensive ecosystem for building robust, enterprise-grade AI solutions. This strategic move aligns perfectly with Microsoft&amp;#39;s overarching goal: to control and streamline the entire AI ecosystem, from foundational models and on-device experiences to specialized agents and the essential tools developers use to build the future. Microsoft&amp;#39;s deliberate decision to release POML as an open-source project is a profound strategic maneuver, extending far beyond a simple act of benevolence. By embracing open-source principles, Microsoft actively encourages wider adoption, fosters community contributions , and strategically positions POML to potentially emerge as an industry standard for prompt orchestration. This move significantly strengthens their broader AI ecosystem encompassing Visual Studio Code, Azure, and GitHub by providing a crucial missing piece for structured LLM application development. This approach is a classic &amp;quot;embrace, extend, and establish&amp;quot; strategy, designed to solidify Microsoft&amp;#39;s leadership and influence within the highly competitive AI landscape. The ultimate success and widespread impact of POML will depend not only on its inherent technical merits but also, crucially, on its ability to cultivate a vibrant and engaged community and to integrate seamlessly into diverse developer toolchains, thereby reinforcing Microsoft&amp;#39;s strategic position in the evolving AI market.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Prompt Orchestration Markup Language (POML): The Blueprint for the Next AI Revolution, accessed on August 20, 2025, &lt;a href=&quot;https://medium.com/@pradipirkar007/prompt-orchestration-markup-language-poml-the-blueprint-for-the-next-ai-revolution-e6c5da1c7a00&quot;&gt;https://medium.com/@pradipirkar007/prompt-orchestration-markup-language-poml-the-blueprint-for-the-next-ai-revolution-e6c5da1c7a00&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Getting Started - POML Documentation, accessed on August 20, 2025, &lt;a href=&quot;https://microsoft.github.io/poml/latest/&quot;&gt;https://microsoft.github.io/poml/latest/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;POML - Visual Studio Marketplace, accessed on August 20, 2025, &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=poml-team.poml&quot;&gt;https://marketplace.visualstudio.com/items?itemName=poml-team.poml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft releases Prompt Orchestration Markup Language : r/LocalLLaMA - Reddit, accessed on August 20, 2025, &lt;a href=&quot;https://www.reddit.com/r/LocalLLaMA/comments/1mo9vkh/microsoft_releases_prompt_orchestration_markup/&quot;&gt;https://www.reddit.com/r/LocalLLaMA/comments/1mo9vkh/microsoft_releases_prompt_orchestration_markup/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft Launches POML: Making Prompt Engineering Structured &amp;amp; Developer-Friendly, accessed on August 20, 2025, &lt;a href=&quot;https://dev.to/bhuvaneshm_dev/microsoft-launches-poml-making-prompt-engineering-structured-developer-friendly-4a6h&quot;&gt;https://dev.to/bhuvaneshm_dev/microsoft-launches-poml-making-prompt-engineering-structured-developer-friendly-4a6h&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft Releases POML (Prompt Orchestration Markup Language): Bringing Modularity and Scalability to LLM Prompts - MarkTechPost, accessed on August 20, 2025, &lt;a href=&quot;https://www.marktechpost.com/2025/08/13/microsoft-releases-poml-prompt-orchestration-markup-language/&quot;&gt;https://www.marktechpost.com/2025/08/13/microsoft-releases-poml-prompt-orchestration-markup-language/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft POML: Can This New AI Markup Language Revolutionize Prompt Engineering? | by AdaGao | Aug, 2025 | Medium, accessed on August 20, 2025, &lt;a href=&quot;https://medium.com/@AdaGaoYY/microsoft-poml-can-this-new-ai-markup-language-revolutionize-prompt-engineering-c686ad3adbed&quot;&gt;https://medium.com/@AdaGaoYY/microsoft-poml-can-this-new-ai-markup-language-revolutionize-prompt-engineering-c686ad3adbed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft POML : Programming Language for Prompting | by Mehul Gupta | Data Science in Your Pocket | Aug, 2025 | Medium, accessed on August 20, 2025, &lt;a href=&quot;https://medium.com/data-science-in-your-pocket/microsoft-poml-programming-language-for-prompting-adfc846387a4&quot;&gt;https://medium.com/data-science-in-your-pocket/microsoft-poml-programming-language-for-prompting-adfc846387a4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Quick Start - POML Documentation, accessed on August 20, 2025, &lt;a href=&quot;https://microsoft.github.io/poml/latest/language/quickstart/&quot;&gt;https://microsoft.github.io/poml/latest/language/quickstart/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;“AI Research Roundup: Meta&amp;#39;s DINOv3, Google&amp;#39;s Nano ..., accessed on August 20, 2025, &lt;a href=&quot;https://ai.plainenglish.io/ai-research-roundup-metas-dinov3-google-s-nano-bytedance-s-tooltrain-microsoft-s-poml-2bf6eb9a9698?source=rss----78d064101951---4&quot;&gt;https://ai.plainenglish.io/ai-research-roundup-metas-dinov3-google-s-nano-bytedance-s-tooltrain-microsoft-s-poml-2bf6eb9a9698?source=rss----78d064101951---4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Visual Studio: IDE and Code Editor for Software Development, accessed on August 20, 2025, &lt;a href=&quot;https://visualstudio.microsoft.com/&quot;&gt;https://visualstudio.microsoft.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Data Handling - GeeksforGeeks, accessed on August 20, 2025, &lt;a href=&quot;https://www.geeksforgeeks.org/maths/data-handling/&quot;&gt;https://www.geeksforgeeks.org/maths/data-handling/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft POML Adds HTML-Style Structure to AI Prompts - Petri IT Knowledgebase, accessed on August 20, 2025, &lt;a href=&quot;https://petri.com/microsoft-poml-html-style-structure-ai-prompts/&quot;&gt;https://petri.com/microsoft-poml-html-style-structure-ai-prompts/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Overview - POML Documentation - Microsoft Open Source, accessed on August 20, 2025, &lt;a href=&quot;https://microsoft.github.io/poml/latest/typescript/&quot;&gt;https://microsoft.github.io/poml/latest/typescript/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Overview - POML Documentation, accessed on August 20, 2025, &lt;a href=&quot;https://microsoft.github.io/poml/latest/python/&quot;&gt;https://microsoft.github.io/poml/latest/python/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Semantic Kernel Agent Orchestration | Microsoft Learn, accessed on August 20, 2025, &lt;a href=&quot;https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-orchestration/&quot;&gt;https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-orchestration/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Designing Multi‑Agent AI Systems with Semantic Kernel | Amgad ..., accessed on August 20, 2025, &lt;a href=&quot;https://amgadmadkour.com/blog/2025/semantickernel/&quot;&gt;https://amgadmadkour.com/blog/2025/semantickernel/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How we built our multi-agent research system - Anthropic, accessed on August 20, 2025, &lt;a href=&quot;https://www.anthropic.com/engineering/built-multi-agent-research-system&quot;&gt;https://www.anthropic.com/engineering/built-multi-agent-research-system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Simon Willison on agent-definitions, accessed on August 20, 2025, &lt;a href=&quot;https://simonwillison.net/tags/agent-definitions/&quot;&gt;https://simonwillison.net/tags/agent-definitions/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;POML: Prompt Orchestration Markup Language | Hacker News, accessed on August 20, 2025, &lt;a href=&quot;https://news.ycombinator.com/item?id=44853184&quot;&gt;https://news.ycombinator.com/item?id=44853184&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Extended POML - POML Documentation - Microsoft Open Source, accessed on August 20, 2025, &lt;a href=&quot;https://microsoft.github.io/poml/latest/language/proposals/poml_extended/&quot;&gt;https://microsoft.github.io/poml/latest/language/proposals/poml_extended/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Can Large Language Models Understand Intermediate Representations in Compilers?, accessed on August 20, 2025, &lt;a href=&quot;https://icml.cc/virtual/2025/poster/43488&quot;&gt;https://icml.cc/virtual/2025/poster/43488&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AI &amp; Machine Learning</category><category>Developer Tools</category><category>Software Engineering</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0085-microsoft-poml-orchestrating-ai-prompts-for-llms/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Compliance as Code: Making Security Easier with Terraform and InSpec</title><link>https://mkabumattar.com/blog/post/compliance-as-code-nist-iso-27001-gdpr-terraform-inspec/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/compliance-as-code-nist-iso-27001-gdpr-terraform-inspec/</guid><description>Learn how to use Compliance as Code with Terraform and InSpec to automatically follow NIST, ISO 27001, and GDPR. Understand the benefits, challenges, and real-world uses of this modern way to handle security and regulatory compliance.</description><pubDate>Sun, 03 Aug 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hey, so you know how keeping our tech stuff secure and following all the rules can be a real headache these days? With everything moving to the cloud and so many regulations popping up, it&amp;#39;s tough to keep track. That&amp;#39;s where &lt;strong&gt;compliance as code&lt;/strong&gt; comes in, and it&amp;#39;s actually a pretty cool idea.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;So, What&amp;#39;s the Deal with Compliance as Code?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Think of &lt;strong&gt;compliance as code&lt;/strong&gt; as baking security and rule-following right into how we build and run our software. Instead of just checking things at the end, we&amp;#39;re making sure everything&amp;#39;s up to snuff from the very beginning, almost like setting up guardrails in code. Basically, we&amp;#39;re turning those long lists of compliance rules into automated tests that our systems have to pass before they can go live. The whole point is to make sure we&amp;#39;re always meeting the necessary standards, both the ones from the government and the ones we set for ourselves. It&amp;#39;s about automating the whole compliance process, from setting things up to checking them, fixing issues, keeping an eye on things, and even creating reports. At the end of the day, &lt;strong&gt;compliance as code&lt;/strong&gt; is all about making compliance a built-in, automatic part of our digital world.&lt;/p&gt;
&lt;p&gt;This is a big step up from the old way of doing things, where we&amp;#39;d usually have manual checks every now and then. Instead of scrambling to fix problems right before an &lt;strong&gt;audit&lt;/strong&gt; or after something goes wrong, &lt;strong&gt;compliance as code&lt;/strong&gt; helps us be proactive and catch issues early on. This &amp;quot;shift left&amp;quot; approach means we can stop problems before they even happen, which saves us a ton of time and effort. Plus, it fits right in with the whole &amp;quot;everything as code&amp;quot; idea, where we&amp;#39;ve already seen how using code to manage our infrastructure (&lt;strong&gt;Terraform&lt;/strong&gt;, anyone?) has been a game-changer. By bringing that same approach to compliance, we can use things like version control, automation, and teamwork to make sure we&amp;#39;re following the rules in a much smarter and more reliable way.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why All the Fuss About Compliance These Days?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;You might be wondering why compliance has become such a big deal. Well, there are a few key reasons.&lt;/p&gt;
&lt;p&gt;First off, the rules are getting more and more complicated. There are tons of security standards and compliance rules out there, like SOC 2, &lt;strong&gt;ISO 27001&lt;/strong&gt;, PCI DSS, HIPAA, &lt;strong&gt;GDPR&lt;/strong&gt;, and &lt;strong&gt;NIST&lt;/strong&gt;. These tell us how we need to operate legally and ethically, especially when it comes to keeping sensitive information safe and managing risks. Take the &lt;strong&gt;GDPR&lt;/strong&gt;, for example, which has really strict rules about protecting the personal information of people in Europe. Or &lt;strong&gt;NIST&lt;/strong&gt; frameworks, which are a must for US government agencies and anyone working with them. And then there&amp;#39;s &lt;strong&gt;ISO 27001&lt;/strong&gt;, which is a standard recognized worldwide for setting up and managing information security. With so many rules, and sometimes they even overlap, trying to manage everything manually can get messy and lead to mistakes.&lt;/p&gt;
&lt;p&gt;Second, cyberattacks are becoming more common and more sophisticated. It feels like we hear about a new one every week, right? That&amp;#39;s why it&amp;#39;s so important to have strong security measures in place. If our network security isn&amp;#39;t tight or if our cloud setups aren&amp;#39;t configured correctly, it can leave us wide open to attacks. Scary enough, a lot of data breaches happen because of misconfigured storage in the cloud, which just shows how crucial it is to have solid and consistent security controls. We really need to move beyond just reacting to attacks after they happen and start being proactive, with continuous monitoring and automated enforcement.&lt;/p&gt;
&lt;p&gt;Finally, the consequences of not following the rules can be pretty serious. We&amp;#39;re talking big fines, legal trouble, and a damaged reputation that can be hard to recover from. Data breaches, in particular, don&amp;#39;t just cost us money right away; they can also make customers lose trust in us, which can hurt our business in the long run. For some standards, like &lt;strong&gt;ISO 27001&lt;/strong&gt;, not staying compliant can even mean losing your certification, which can be a big deal for certain business opportunities. All these potential downsides really highlight why we need to use effective and automated ways to manage compliance and protect ourselves.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How NIST, ISO 27001, GDPR, and Compliance as Code Work Together&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;So, how do specific sets of rules like &lt;strong&gt;NIST&lt;/strong&gt;, &lt;strong&gt;ISO 27001&lt;/strong&gt;, and &lt;strong&gt;GDPR&lt;/strong&gt; fit into this whole &lt;strong&gt;compliance as code&lt;/strong&gt; picture?&lt;/p&gt;
&lt;p&gt;The National Institute of Standards and Technology (&lt;strong&gt;NIST&lt;/strong&gt;) has put together a really thorough set of guidelines and best practices to help organizations beef up their cybersecurity and handle risks effectively. If you&amp;#39;re a US federal government agency or a contractor working with them, you often have to comply with &lt;strong&gt;NIST&lt;/strong&gt; frameworks. Because &lt;strong&gt;NIST&lt;/strong&gt; guidelines are usually very detailed and specific, they&amp;#39;re perfect for turning into code. We can use tools like &lt;strong&gt;Terraform&lt;/strong&gt; to translate those &lt;strong&gt;NIST&lt;/strong&gt; security rules into infrastructure code, which means we can automate security checks and make sure our setups always meet &lt;strong&gt;NIST&lt;/strong&gt; standards. Plus, tools like &lt;strong&gt;InSpec&lt;/strong&gt; can automatically check if we&amp;#39;re still compliant, so we can be sure we&amp;#39;re always following the rules.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ISO 27001&lt;/strong&gt; is a standard that&amp;#39;s recognized around the world. It gives us a framework for setting up, putting in place, maintaining, and constantly improving an Information Security Management System (ISMS). It&amp;#39;s a comprehensive way to manage and protect all the sensitive information an organization has. Getting &lt;strong&gt;ISO 27001&lt;/strong&gt; certified can show everyone that you&amp;#39;re serious about security and can also help you meet other rules, like &lt;strong&gt;GDPR&lt;/strong&gt;, HIPAA, and SOC 2. Setting up an ISMS that follows &lt;strong&gt;ISO 27001&lt;/strong&gt; gives you a solid base for meeting the data security requirements of the &lt;strong&gt;GDPR&lt;/strong&gt;. The way &lt;strong&gt;ISO 27001&lt;/strong&gt; looks at risk and the detailed security measures it suggests can be really well implemented and checked using &lt;strong&gt;compliance as code&lt;/strong&gt;. This gives us a systematic and automated way to handle information security, which lines up nicely with what the &lt;strong&gt;GDPR&lt;/strong&gt; wants us to do.&lt;/p&gt;
&lt;p&gt;The General Data Protection Regulation (&lt;strong&gt;GDPR&lt;/strong&gt;) is a set of rules from the European Union that&amp;#39;s all about protecting people&amp;#39;s data and privacy within the EU. And it doesn&amp;#39;t just apply to companies in Europe; if you&amp;#39;re dealing with the personal data of anyone in the EU, you&amp;#39;ve got to follow these rules. The &lt;strong&gt;GDPR&lt;/strong&gt; says that organizations need to have good technical and organizational measures in place to make sure the personal data they handle is secure and protected. Like we talked about, &lt;strong&gt;ISO 27001&lt;/strong&gt; is a great framework for meeting those technical and operational needs for &lt;strong&gt;GDPR&lt;/strong&gt; compliance. And what&amp;#39;s really cool is that tools like &lt;strong&gt;InSpec&lt;/strong&gt; are perfect for automatically checking if our systems meet the specific technical requirements of the &lt;strong&gt;GDPR&lt;/strong&gt;, so we can keep an eye on our compliance all the time. The main idea behind the &lt;strong&gt;GDPR&lt;/strong&gt;, which is &amp;quot;privacy by design,&amp;quot; fits perfectly with the proactive nature of &lt;strong&gt;compliance as code&lt;/strong&gt;. It lets us build privacy and security into our systems and processes right from the start and constantly check if we&amp;#39;re still meeting the &lt;strong&gt;GDPR&lt;/strong&gt;&amp;#39;s tough standards.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Framework&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Origin/Scope&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Key Focus Areas&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Relevance to Compliance as Code&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;NIST&lt;/td&gt;
&lt;td&gt;US Federal Government &amp;amp; Contractors&lt;/td&gt;
&lt;td&gt;Cybersecurity Framework, Risk Management&lt;/td&gt;
&lt;td&gt;Detailed guidelines can be turned into code and enforced using Terraform and checked with InSpec.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ISO 27001&lt;/td&gt;
&lt;td&gt;International Standard&lt;/td&gt;
&lt;td&gt;Information Security Management System (ISMS)&lt;/td&gt;
&lt;td&gt;Risk-based controls can be set up with Terraform and checked for effectiveness with InSpec.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GDPR&lt;/td&gt;
&lt;td&gt;European Union&lt;/td&gt;
&lt;td&gt;Data Protection and Privacy&lt;/td&gt;
&lt;td&gt;Technical requirements can be turned into InSpec checks and infrastructure managed by Terraform.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Terraform and InSpec: The Power Duo for Compliance as Code&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Two really helpful tools that make &lt;strong&gt;compliance as code&lt;/strong&gt; possible are &lt;strong&gt;Terraform&lt;/strong&gt; and &lt;strong&gt;InSpec&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Terraform&lt;/strong&gt; is a popular open-source tool that lets us define and manage our infrastructure using code, whether it&amp;#39;s on different cloud providers or our own servers. It&amp;#39;s super useful for &lt;strong&gt;compliance as code&lt;/strong&gt; because it lets us put our governance rules right into our infrastructure setup, making sure they&amp;#39;re applied consistently everywhere. &lt;strong&gt;Terraform&lt;/strong&gt; helps us enforce security rules at the infrastructure level, like setting up secure storage, putting in place strong network controls, and managing who has access to what. Because it works so well with CI/CD pipelines, we can make sure our security and compliance rules are followed even before we deploy anything to production. Plus, it can connect with services like AWS Config to continuously monitor for any changes in our setup. Basically, &lt;strong&gt;Terraform&lt;/strong&gt; gives us the foundation for &lt;strong&gt;compliance as code&lt;/strong&gt; by letting us define how we want our infrastructure to look, including all the security and compliance bits, in a way that&amp;#39;s version-controlled, repeatable, and easy to audit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;InSpec&lt;/strong&gt;, on the other hand, is an open-source tool specifically designed for automatically testing the security and compliance of our infrastructure, applications, and other tech stuff. It lets security and compliance teams write down their rules and requirements in a way that&amp;#39;s easy for humans to read, which makes it simpler to turn those regulatory standards into tests that can actually be run. We can use &lt;strong&gt;InSpec&lt;/strong&gt; to check the infrastructure that &lt;strong&gt;Terraform&lt;/strong&gt; sets up, making sure that what we&amp;#39;ve actually got matches the compliant setup we defined in our &lt;strong&gt;Terraform&lt;/strong&gt; code. It&amp;#39;s like the &amp;quot;test&amp;quot; part of the equation, making sure that everything &lt;strong&gt;Terraform&lt;/strong&gt; and other tools deploy follows the security and compliance standards we need. &lt;strong&gt;InSpec&lt;/strong&gt; gives us the continuous checking and validation we need to keep our environment compliant.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Terraform&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;InSpec&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;How it Enables Compliance as Code&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Infrastructure Provisioning&lt;/td&gt;
&lt;td&gt;Defines and deploys infrastructure as code using a declarative language.&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Ensures infrastructure is set up in a way that meets our compliance needs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance Testing&lt;/td&gt;
&lt;td&gt;Primarily focuses on infrastructure setup. Can work with policy tools.&lt;/td&gt;
&lt;td&gt;Specifically designed for automated security and compliance testing of infrastructure and applications.&lt;/td&gt;
&lt;td&gt;Checks that the infrastructure and applications we&amp;#39;ve set up meet our compliance rules and regulatory requirements.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Policy Enforcement&lt;/td&gt;
&lt;td&gt;Can be extended with policy as code tools like Sentinel and OPA.&lt;/td&gt;
&lt;td&gt;Can define compliance rules as code that can be run automatically.&lt;/td&gt;
&lt;td&gt;Allows us to both prevent issues (Terraform with policy tools) and detect them (InSpec) to make sure we&amp;#39;re compliant.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reporting&lt;/td&gt;
&lt;td&gt;Shows us the state of our infrastructure.&lt;/td&gt;
&lt;td&gt;Creates detailed reports on the results of our compliance checks.&lt;/td&gt;
&lt;td&gt;Gives us proof that we&amp;#39;re compliant, both for ourselves and for when we have to show it to others during &lt;strong&gt;audits&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Putting Compliance into Practice for NIST, ISO 27001, and GDPR with Terraform&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To really make &lt;strong&gt;compliance as code&lt;/strong&gt; work for &lt;strong&gt;NIST&lt;/strong&gt;, &lt;strong&gt;ISO 27001&lt;/strong&gt;, and &lt;strong&gt;GDPR&lt;/strong&gt; using &lt;strong&gt;Terraform&lt;/strong&gt;, there are a few important things we need to do.&lt;/p&gt;
&lt;p&gt;First, we&amp;#39;ve got to carefully translate the specific technical rules and requirements of these frameworks into actual &lt;strong&gt;Terraform&lt;/strong&gt; code. This means really understanding each framework and how its rules apply to the settings and configurations of our cloud resources. For example, if &lt;strong&gt;NIST&lt;/strong&gt; says we need to encrypt our data, we can use &lt;strong&gt;Terraform&lt;/strong&gt; to make sure that services like S3 buckets and databases are always encrypted. Similarly, for &lt;strong&gt;GDPR&lt;/strong&gt;, our &lt;strong&gt;Terraform&lt;/strong&gt; code can make sure that all personal data, whether it&amp;#39;s being stored or moved around, is encrypted using strong methods and that only the right people have access. To align with &lt;strong&gt;ISO 27001&lt;/strong&gt;&amp;#39;s focus on who can access what and keeping logs, we can use &lt;strong&gt;Terraform&lt;/strong&gt; to set up detailed access rules, configure logging for all sorts of resources, and divide our network into secure sections. It&amp;#39;s super important to get this translation right, turning those sometimes abstract compliance rules into the specific settings that &lt;strong&gt;Terraform&lt;/strong&gt; can manage. This often means that the people who know the compliance stuff need to work closely with the engineers who know &lt;strong&gt;Terraform&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Second, it&amp;#39;s a good idea to use reusable &lt;strong&gt;Terraform&lt;/strong&gt; modules as much as possible. This helps make sure everything is consistent and reduces the chance of mistakes in our setup. These modules are like pre-approved, compliant building blocks that we can use across different projects and environments, so we know we&amp;#39;re always meeting our compliance standards. For instance, we could have a module for creating a virtual machine in AWS that&amp;#39;s already set up with the right security rules, access permissions, and encryption settings. Using these well-defined and compliant &lt;strong&gt;Terraform&lt;/strong&gt; modules helps us keep things standard across our organization, making it easier to manage and maintain compliance as we grow, and it also helps us avoid human errors in our configurations.&lt;/p&gt;
&lt;p&gt;Finally, adding Policy as Code tools to &lt;strong&gt;Terraform&lt;/strong&gt; gives us even more control and automation. Tools like HashiCorp Sentinel or Open Policy Agent (OPA) let us define and enforce really specific rules on our &lt;strong&gt;Terraform&lt;/strong&gt; setups. These rules can check for anything that might violate our organizational standards or regulatory requirements &lt;em&gt;before&lt;/em&gt; we even set up the infrastructure, acting like preventative measures. For example, we could have a Sentinel policy that stops us from creating an S3 bucket if it doesn&amp;#39;t have encryption turned on, or that limits the types of virtual machines we can use to only those that meet our security needs. Policy as Code tools give us an extra layer of control and automation, letting us enforce complex compliance rules that go beyond what &lt;strong&gt;Terraform&lt;/strong&gt; can do on its own, making sure that only compliant infrastructure ever gets deployed.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Automated Compliance Audits with InSpec: Keeping Things in Check&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;InSpec&lt;/strong&gt; is key to making sure we have continuous governance through automated compliance &lt;strong&gt;audits&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;One of the main things it does is check the infrastructure that &lt;strong&gt;Terraform&lt;/strong&gt; has set up. It does this by running &lt;strong&gt;InSpec&lt;/strong&gt; tests (also called controls) that look at the configuration and status of our cloud resources and compare them to the specific rules of &lt;strong&gt;NIST&lt;/strong&gt;, &lt;strong&gt;ISO 27001&lt;/strong&gt;, and &lt;strong&gt;GDPR&lt;/strong&gt;. For example, an &lt;strong&gt;InSpec&lt;/strong&gt; test can check if an AWS security group created by &lt;strong&gt;Terraform&lt;/strong&gt; has the right incoming and outgoing traffic rules, according to our security policy. Similarly, &lt;strong&gt;InSpec&lt;/strong&gt; can make sure that a database we set up with &lt;strong&gt;Terraform&lt;/strong&gt; is encrypted when it&amp;#39;s not being used, that logging is turned on, and that the right people have access. These &lt;strong&gt;InSpec&lt;/strong&gt; tests act like automated &lt;strong&gt;audits&lt;/strong&gt;, constantly looking at our deployed infrastructure to confirm that it&amp;#39;s following the security and compliance standards we&amp;#39;ve set and that the regulations require.&lt;/p&gt;
&lt;p&gt;To really keep things in check, we should put these &lt;strong&gt;InSpec&lt;/strong&gt; tests right into our CI/CD pipelines. This way, every time we make a change to our infrastructure, it automatically gets checked for compliance before it goes live. If an &lt;strong&gt;InSpec&lt;/strong&gt; test fails during this process, it means the change we&amp;#39;re trying to make would break a compliance rule, and the deployment can be stopped automatically. This prevents any non-compliant resources from ever making it to our production environment. This creates a &amp;quot;compliance gate,&amp;quot; making sure that only infrastructure that meets our security and regulatory standards can be deployed, which moves our compliance checks even earlier in the development process.&lt;/p&gt;
&lt;p&gt;On top of that, &lt;strong&gt;InSpec&lt;/strong&gt; can create detailed and easy-to-read reports that summarize the results of our compliance &lt;strong&gt;audits&lt;/strong&gt;. These reports clearly show which tests (controls) passed and which ones failed, giving us a clear picture of our compliance status. These reports are really valuable for our internal teams, management, and even external &lt;strong&gt;audits&lt;/strong&gt;, because they provide evidence that we&amp;#39;re following the security and compliance standards we need to. The reporting features of &lt;strong&gt;InSpec&lt;/strong&gt; make the &lt;strong&gt;audit&lt;/strong&gt; process much easier by giving us readily available and comprehensive documentation of our compliance checks, making it simpler to show that we&amp;#39;re meeting regulations and our own internal policies.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;The Real Benefits of Using Compliance as Code&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;There are a lot of real advantages to using &lt;strong&gt;compliance as code&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;First off, it makes our security stronger. By finding and fixing security weaknesses and compliance issues early on, we can stop them from ever reaching our live systems. Making sure our security rules are consistently applied across all our infrastructure reduces the chance of mistakes and human errors. Ultimately, by building security checks into our infrastructure and development processes, we significantly lower the risk of data breaches and security problems.&lt;/p&gt;
&lt;p&gt;Second, it helps us meet regulations better. Automated checks make sure we&amp;#39;re constantly following the specific technical rules of frameworks like &lt;strong&gt;NIST&lt;/strong&gt;, &lt;strong&gt;ISO 27001&lt;/strong&gt;, and &lt;strong&gt;GDPR&lt;/strong&gt;, which means we&amp;#39;re less likely to be non-compliant. &lt;strong&gt;Audits&lt;/strong&gt; become much simpler and less disruptive because we have automated proof of our compliance ready to go. By consistently meeting regulatory requirements, we can avoid those big fines and legal issues that come with non-compliance.&lt;/p&gt;
&lt;p&gt;Third, &lt;strong&gt;compliance as code&lt;/strong&gt; makes us more efficient and agile. Automation really cuts down on the manual work involved in checking compliance, doing &lt;strong&gt;audits&lt;/strong&gt;, and fixing problems, which frees up our IT teams to do other important things. Compliance issues get found and fixed much faster with automated checks, so we don&amp;#39;t have as many delays in our development and deployment processes. By giving developers built-in compliance guidelines, it lets them move faster and be more innovative without worrying about breaking security or regulatory rules.&lt;/p&gt;
&lt;p&gt;Finally, it saves us money. Automating compliance processes means we don&amp;#39;t need as many people on dedicated compliance teams, which can lead to significant savings. By proactively preventing data breaches and security incidents, we avoid the big financial losses that come with those events, including fines, recovery costs, and damage to our reputation. And the improved efficiency from automation and less rework also helps us save money overall.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Things to Keep in Mind When Using Compliance as Code&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Even though &lt;strong&gt;compliance as code&lt;/strong&gt; has a lot of great benefits, there are some challenges to think about.&lt;/p&gt;
&lt;p&gt;One big thing is the change in how people work together. Using &lt;strong&gt;compliance as code&lt;/strong&gt; often means that development, security, and compliance teams need to change their mindsets and how they do things, and that can be tough if it&amp;#39;s not managed well. Organizations that aren&amp;#39;t used to agile and automation might find this transition especially hard. For it to work, there needs to be good teamwork and everyone needs to understand their role in compliance.&lt;/p&gt;
&lt;p&gt;Another thing is the initial setup and how complex it can be. Figuring out all the governance rules and then turning them into code that actually works can take a lot of time and effort. It also requires people who really understand the compliance frameworks and who are good at using the automation tools like &lt;strong&gt;Terraform&lt;/strong&gt; and &lt;strong&gt;InSpec&lt;/strong&gt;. Teams might also need some time to learn how to use these new tools and frameworks. The initial investment in time, resources, and expertise to get a good &lt;strong&gt;compliance as code&lt;/strong&gt; system up and running can be significant, so it&amp;#39;s something to plan for.&lt;/p&gt;
&lt;p&gt;Also, there are some things that just can&amp;#39;t be fully automated. While &lt;strong&gt;compliance as code&lt;/strong&gt; can handle a lot of the technical parts of compliance, some rules, especially those that need a human to make a judgment or involve manual steps, might be hard or impossible to automate completely. We might still need a mix of automated checks and manual reviews to make sure we&amp;#39;re fully compliant.&lt;/p&gt;
&lt;p&gt;Lastly, good data management is key. We need to make sure that the data we use for our automated compliance checks is available, accurate, and reliable for &lt;strong&gt;compliance as code&lt;/strong&gt; to work well. Organizations also need to be careful about managing sensitive information, like passwords and API keys, that might be used in &lt;strong&gt;Terraform&lt;/strong&gt; files and &lt;strong&gt;InSpec&lt;/strong&gt; tests to avoid security risks.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Compliance as Code in a Bigger Governance Plan&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Compliance as code&lt;/strong&gt; is a really important part of a bigger idea called Governance as Code. Governance as Code takes the ideas of &lt;strong&gt;compliance as code&lt;/strong&gt; and applies them to a wider range of organizational rules, including security, who can access what, data privacy, how much things cost, and how we operate. It&amp;#39;s about defining and enforcing all these rules using automation and code, so we don&amp;#39;t have to rely as much on manual processes and we can make sure things are consistent across our IT infrastructure.&lt;/p&gt;
&lt;p&gt;Policy as Code is what makes both &lt;strong&gt;compliance as code&lt;/strong&gt; and Governance as Code possible. It&amp;#39;s about representing our rules and standards as code that can be automatically checked and enforced. When it comes to compliance, Policy as Code lets us turn our compliance requirements into code, so we can automatically find any violations and make sure our cloud resources and applications are meeting the necessary standards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compliance as code&lt;/strong&gt; also helps us with continuous monitoring and improvement. It lets us constantly watch our infrastructure and applications to make sure they&amp;#39;re following our compliance rules, giving us real-time information about our compliance status. This continuous monitoring helps us catch any changes that might make us non-compliant early on, so we can fix them before they cause security problems or make us fail an &lt;strong&gt;audit&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions About Compliance as Code with Terraform and InSpec&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the main ideas behind Compliance as Code?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Writing down compliance rules and security policies as code using a clear language.&lt;/li&gt;
&lt;li&gt;Automatically checking if our infrastructure and applications follow these rules.&lt;/li&gt;
&lt;li&gt;Putting these compliance checks right into our software development and deployment process.&lt;/li&gt;
&lt;li&gt;Constantly watching and giving us updates on the compliance status of our tech resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does ISO 27001 help with GDPR compliance?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ISO 27001&lt;/strong&gt; gives us a strong framework for setting up an Information Security Management System (ISMS), which covers a lot of the technical and organizational things we need to do for &lt;strong&gt;GDPR&lt;/strong&gt; to protect personal data.&lt;/li&gt;
&lt;li&gt;The way it looks at risk helps organizations find and deal with risks to personal data, which is what &lt;strong&gt;GDPR&lt;/strong&gt; wants us to do.&lt;/li&gt;
&lt;li&gt;Getting certified in &lt;strong&gt;ISO 27001&lt;/strong&gt; can show that we&amp;#39;ve taken the right security steps to meet &lt;strong&gt;GDPR&lt;/strong&gt;&amp;#39;s data security rules&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can Terraform help us follow NIST rules?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Terraform&lt;/strong&gt; lets us write down &lt;strong&gt;NIST&lt;/strong&gt; security guidelines as code in our infrastructure setups.&lt;/li&gt;
&lt;li&gt;By using &lt;strong&gt;Terraform&lt;/strong&gt;&amp;#39;s language, we can say exactly how we want our infrastructure to be set up to meet &lt;strong&gt;NIST&lt;/strong&gt; standards.&lt;/li&gt;
&lt;li&gt;We can say exactly how we want our infrastructure to be set up to meet &lt;strong&gt;NIST&lt;/strong&gt; standards.&lt;/li&gt;
&lt;li&gt;Connecting it with policy tools like Sentinel lets us check if we&amp;#39;re meeting &lt;strong&gt;NIST&lt;/strong&gt; rules even before we deploy anything.&lt;/li&gt;
&lt;li&gt;We can also use &lt;strong&gt;Terraform&lt;/strong&gt; to set up specific security settings that &lt;strong&gt;NIST&lt;/strong&gt; recommends for different cloud resources, like encryption, access controls, and logging.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does InSpec do compliance audits for GDPR?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;InSpec&lt;/strong&gt; lets security and compliance teams turn the technical rules of &lt;strong&gt;GDPR&lt;/strong&gt; into code that can be run automatically (&lt;strong&gt;InSpec&lt;/strong&gt; controls).&lt;/li&gt;
&lt;li&gt;These controls can then be run against our systems and infrastructure to check if they&amp;#39;re meeting &lt;strong&gt;GDPR&lt;/strong&gt;&amp;#39;s data protection standards.&lt;/li&gt;
&lt;li&gt;By putting &lt;strong&gt;InSpec&lt;/strong&gt; into our CI/CD pipelines, we can make sure our systems are constantly being checked against &lt;strong&gt;GDPR&lt;/strong&gt; rules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;InSpec&lt;/strong&gt; gives us detailed reports on our compliance status, pointing out anything that doesn&amp;#39;t meet &lt;strong&gt;GDPR&lt;/strong&gt;&amp;#39;s technical requirements.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the good things about using Compliance as Code?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;It makes our compliance practices more consistent and standard across the whole organization.&lt;/li&gt;
&lt;li&gt;It&amp;#39;s easier to scale our compliance efforts as our infrastructure grows.&lt;/li&gt;
&lt;li&gt;We can save a lot of money by automating things and reducing manual work.&lt;/li&gt;
&lt;li&gt;It helps us keep up with compliance rules that change often.&lt;/li&gt;
&lt;li&gt;It improves teamwork and understanding between development, security, and compliance teams.&lt;/li&gt;
&lt;li&gt;It gives us continuous monitoring and enforcement of compliance, making our security stronger.&lt;/li&gt;
&lt;li&gt;It makes delivering software faster and more efficiently by building compliance into the development process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audits&lt;/strong&gt; become simpler because we have automated ways to collect evidence and create reports.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some of the challenges of using Compliance as Code?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;People might not like changing to new agile and automation ways of working.&lt;/li&gt;
&lt;li&gt;It can be hard to figure out and write down all the compliance rules accurately as code.&lt;/li&gt;
&lt;li&gt;Some compliance rules that need human judgment can&amp;#39;t be fully automated.&lt;/li&gt;
&lt;li&gt;We need people who know both the compliance rules and the automation tools (&lt;strong&gt;Terraform&lt;/strong&gt;, &lt;strong&gt;InSpec&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;We need to manage and protect sensitive information used in our automation processes carefully.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Where can I find examples of Compliance as Code using Terraform and InSpec?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Chef&amp;#39;s blog has some good examples of how to use &lt;strong&gt;InSpec&lt;/strong&gt; to check if infrastructure set up by &lt;strong&gt;Terraform&lt;/strong&gt; is compliant, especially in AWS.&lt;/li&gt;
&lt;li&gt;The official documentation and community forums for &lt;strong&gt;Terraform&lt;/strong&gt; and &lt;strong&gt;InSpec&lt;/strong&gt; often have practical examples and ways to use them for &lt;strong&gt;Compliance as Code&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You can often find examples of &lt;strong&gt;Terraform&lt;/strong&gt; modules and &lt;strong&gt;InSpec&lt;/strong&gt; profiles for specific compliance standards on platforms like GitHub.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;p&gt;&lt;strong&gt;Wrapping Up: Looking Ahead with Compliance as Code&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compliance as code&lt;/strong&gt; is a really important step forward in how organizations handle the complexities of security and following the rules in today&amp;#39;s digital world. By building security and compliance checks right into our infrastructure and development processes, we can be more proactive, efficient, and reliable in how we govern ourselves. Tools like &lt;strong&gt;Terraform&lt;/strong&gt; and &lt;strong&gt;InSpec&lt;/strong&gt; give us the power to define, deploy, and constantly check our compliance with important frameworks like &lt;strong&gt;NIST&lt;/strong&gt;, &lt;strong&gt;ISO 27001&lt;/strong&gt;, and &lt;strong&gt;GDPR&lt;/strong&gt;. While there might be some hurdles in getting started with &lt;strong&gt;compliance as code&lt;/strong&gt;, the big benefits it offers in terms of better security, improved compliance, increased efficiency, and cost savings make it a must-have for organizations navigating the cloud era. Embracing &lt;strong&gt;compliance as code&lt;/strong&gt; isn&amp;#39;t just a tech trend; it&amp;#39;s a fundamental shift towards a more automated, proactive, and ultimately more secure and compliant way of running our digital operations.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Compliance as Code: Tutorial + Best Practices - Drata, accessed on May 16, 2025, &lt;a href=&quot;https://drata.com/grc-central/compliance-as-code/what-is-cac&quot;&gt;https://drata.com/grc-central/compliance-as-code/what-is-cac&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Compliance as Code? The Best Way to Automate ... - Puppet, accessed on May 16, 2025, &lt;a href=&quot;https://www.puppet.com/blog/compliance-as-code&quot;&gt;https://www.puppet.com/blog/compliance-as-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Compliance as code | Thoughtworks United States, accessed on May 16, 2025, &lt;a href=&quot;https://www.thoughtworks.com/en-us/insights/decoder/c/compliance-as-code&quot;&gt;https://www.thoughtworks.com/en-us/insights/decoder/c/compliance-as-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Is Compliance as Code? Benefits, Use Cases and Tools ..., accessed on May 16, 2025, &lt;a href=&quot;https://www.contino.io/insights/compliance-as-code&quot;&gt;https://www.contino.io/insights/compliance-as-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Compliance Made Simple with Terraform | ControlMonkey, accessed on May 16, 2025, &lt;a href=&quot;https://controlmonkey.io/blog/compliance-made-simple-with-terraform-cloud-governess/&quot;&gt;https://controlmonkey.io/blog/compliance-made-simple-with-terraform-cloud-governess/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using InSpec to DevOps GDPR compliance - Joe Gardiner, accessed on May 16, 2025, &lt;a href=&quot;https://grdnr.io/post/2017-08-12-using-inspec-to-devops-gdpr-compliance/&quot;&gt;https://grdnr.io/post/2017-08-12-using-inspec-to-devops-gdpr-compliance/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ISO 27001 and Privacy - IT Governance USA, accessed on May 16, 2025, &lt;a href=&quot;https://www.itgovernanceusa.com/cyber-security-solutions/iso27001/iso27001_privacy&quot;&gt;https://www.itgovernanceusa.com/cyber-security-solutions/iso27001/iso27001_privacy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ISO 27001 vs. NIST 800-53: Key Differences and Similarities - Security Compass, accessed on May 16, 2025, &lt;a href=&quot;https://www.securitycompass.com/blog/iso-27001-vs-nist-800-53/&quot;&gt;https://www.securitycompass.com/blog/iso-27001-vs-nist-800-53/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Cloud Compliance? Standards, Solutions &amp;amp; More - Spacelift, accessed on May 16, 2025, &lt;a href=&quot;https://spacelift.io/blog/cloud-compliance&quot;&gt;https://spacelift.io/blog/cloud-compliance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform-Driven Compliance Audits: Enforcing Continuous Cloud Governance in AWS -, accessed on May 16, 2025, &lt;a href=&quot;https://www.cycloid.io/terraform-driven-compliance-audits-enforcing-continuous-cloud-governance-in-aws/&quot;&gt;https://www.cycloid.io/terraform-driven-compliance-audits-enforcing-continuous-cloud-governance-in-aws/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Infrastructure Testing and Compliance with Chef and Terraform, accessed on May 16, 2025, &lt;a href=&quot;https://www.chef.io/blog/infrastructure-testing-and-compliance-with-chef-and-terraform&quot;&gt;https://www.chef.io/blog/infrastructure-testing-and-compliance-with-chef-and-terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Policy as Code Approach: How to Streamline Cloud Governance - EPAM SolutionsHub, accessed on May 16, 2025, &lt;a href=&quot;https://solutionshub.epam.com/blog/post/policy-as-code&quot;&gt;https://solutionshub.epam.com/blog/post/policy-as-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Governance as Code? | Harness, accessed on May 16, 2025, &lt;a href=&quot;https://www.harness.io/harness-devops-academy/what-is-governance-as-code&quot;&gt;https://www.harness.io/harness-devops-academy/what-is-governance-as-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GDPR Compliance Audit Software Solutions | Chef, accessed on May 16, 2025, &lt;a href=&quot;https://www.chef.io/solutions/compliance/gdpr&quot;&gt;https://www.chef.io/solutions/compliance/gdpr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sensitive data Classification for HIPAA,PCI DSS, GDPR, ISO 27001 ,CCPA and More., accessed on May 16, 2025, &lt;a href=&quot;https://www.strac.io/blog/sensitive-data-classification-for-hipaa-pci-dss-gdpr-iso-27001-ccpa-and-more&quot;&gt;https://www.strac.io/blog/sensitive-data-classification-for-hipaa-pci-dss-gdpr-iso-27001-ccpa-and-more&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Compliance as Code</category><category>Security</category><category>DevSecOps</category><category>Terraform</category><category>InSpec</category><category>Cloud</category><category>Governance</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0084-compliance-as-code-nist-iso-27001-gdpr-terraform-inspec/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Low-Code vs. Custom Code: Let&apos;s Talk About Speed and Tech Debt</title><link>https://mkabumattar.com/blog/post/low-code-vs-custom-code-speed-tech-debt/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/low-code-vs-custom-code-speed-tech-debt/</guid><description>Explore the crucial balance between development speed and technical debt when choosing between low-code and custom code. Learn when each approach shines, especially for internal tools like Retool.</description><pubDate>Sat, 21 Jun 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the ever-changing world of making software, there&amp;#39;s always this big question: how do we build things quickly without creating a mess down the road? That&amp;#39;s where &amp;quot;low-code&amp;quot; development comes into play. It&amp;#39;s a way of building software that&amp;#39;s different from the usual &amp;quot;custom code&amp;quot; approach. Custom code gives you lots of control, but it can take a while. So, how do we find that sweet spot where we can build fast but still have a solid system that won&amp;#39;t cause headaches later? That&amp;#39;s what we&amp;#39;re going to explore – balancing speed with something called tech debt.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What&amp;#39;s the Deal with Low-Code Development Anyway?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Basically, low-code development lets you build apps using a visual way of doing things, so you don&amp;#39;t have to write tons of traditional code. Think of it like using building blocks to create something – it&amp;#39;s much faster than making each block from scratch. Gartner, who knows a thing or two about this stuff, says that these low-code platforms help you build and update apps faster using tools that show you the whole app, AI help, and ready-made pieces you can just grab and use. And it&amp;#39;s getting super popular! Gartner thinks that by next year, most companies will be using low-code in some way.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s really driving this is that more and more people who aren&amp;#39;t traditional programmers are getting involved in building apps to solve their own problems. These platforms usually have easy-to-use visual tools, lots of pre-built parts, and they can connect with other systems and data easily. You can build all sorts of apps with them, from simple interfaces to complex ways of automating business stuff. Some even have AI that helps you build and automate things. Plus, good low-code platforms have controls to keep things organized, security built-in, and they can grow as your business grows. Interestingly, a lot of them also let you add your own custom code if you need to do something really specific.&lt;/p&gt;
&lt;p&gt;So, low-code has really grown from a small thing to a pretty big deal because businesses are under pressure to go digital faster, and there aren&amp;#39;t always enough traditional IT folks around. It&amp;#39;s easy to see why building things faster is appealing to both IT departments wanting to work smarter and business people wanting to create their own solutions. This is leading to better teamwork between business and IT, and it&amp;#39;s making app development more accessible to everyone, which could mean we get better tech solutions faster.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Okay, So What About Custom Code Then?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Well, custom code development is the way software used to be built, where you&amp;#39;re creating everything from the ground up. Skilled developers write code using different programming languages to make software that&amp;#39;s exactly what a business needs. The big thing about custom code is that you have total control and lots of flexibility over every little detail of the app, from how it looks to how it works with other systems. This is different from off-the-shelf software that doesn&amp;#39;t let you change much, and low-code options that use pre-made code pieces.&lt;/p&gt;
&lt;p&gt;Usually, custom development is done by professional developers who really know their stuff when it comes to coding. It&amp;#39;s important to remember that custom software needs ongoing maintenance, regular updates, and support from the people who built it to keep it running well. Custom code is still super important for businesses that have really unique ways of working or very specific products that off-the-shelf software just can&amp;#39;t handle. Being able to create software that fits perfectly with how a business works is a huge plus. When standard software doesn&amp;#39;t do exactly what you need, custom code lets you build in very specific logic, connect different systems in unique ways, and make sure security is exactly how you want it.&lt;/p&gt;
&lt;p&gt;While custom code gives you amazing control and tailor-made solutions, it usually costs more upfront and takes longer to develop compared to low-code options that can be much faster. Building software from scratch means you need skilled developers, careful planning, lots of coding, and thorough testing, all of which adds to the time and cost. Businesses have to really think about these things when deciding if the total control of custom code is worth it.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Speed: Why Everyone&amp;#39;s Talking About Low-Code&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;One of the biggest reasons people are excited about low-code is that it can make building software much faster. Low-code platforms speed things up in a few key ways. They have pre-built pieces and easy visual interfaces that let developers, and even people who aren&amp;#39;t really developers, create apps quickly. This means you can get your software out there much faster. By making it easier for business users who know what they need to get involved, low-code frees up the more technical developers to work on the really complicated stuff.&lt;/p&gt;
&lt;p&gt;This speed is great for quickly making prototypes – you can get a working model of your idea up and running fast to get feedback. It&amp;#39;s also really useful for creating Minimum Viable Products (MVPs), which are basic versions of your product that let you test your idea and then improve it based on what people say. Platforms like Retool are a good example of this, especially for building internal tools. Retool makes it easy to connect to different databases and APIs, so you don&amp;#39;t have to spend ages writing code to make those connections. It&amp;#39;s got a bunch of pre-built and customizable components that you can just drag and drop to create your user interface, which really speeds things up. Retool is designed to be low-code or even no-code, but it still lets you add custom code if you need it, making it super fast for building those internal apps that businesses rely on.&lt;/p&gt;
&lt;p&gt;Plus, the speed of low-code can really help with the backlog of IT projects that a lot of companies have, letting them deliver solutions much more quickly. The visual nature and ready-made parts of low-code platforms are what make this faster development possible compared to writing everything from scratch. By taking away a lot of the coding and giving you those ready-to-use pieces, these platforms cut down on the manual work, leading to faster building and deployment. Low-code platforms, especially ones like Retool, are really handy for internal tools because they can quickly connect to existing data and systems, and they focus on making functional interfaces with minimal coding. Internal tools often need to work with different databases and APIs, and low-code platforms that make this easy and have pre-built components for common internal tasks can save a ton of time and effort. This faster development that low-code offers can make businesses more agile, letting them adapt more quickly to what the market wants and what their customers need. Faster cycles mean new features and apps can be rolled out more often, so businesses can try things, get feedback, and refine their plans more efficiently in a fast-moving business world.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;But What About Tech Debt? The Hidden Cost of Speed&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While going fast is great, we&amp;#39;ve got to think about something called technical debt in both low-code and custom code development. Basically, tech debt is like taking shortcuts now that might cost you more time and effort later. With low-code, this can happen if you rely too much on those pre-built pieces and have to find awkward ways to make them do things they weren&amp;#39;t really designed for. This can make things complicated and harder to change later. Also, some low-code platforms don&amp;#39;t let you customize things as much as you might need, which can mean you end up with a solution that&amp;#39;s not quite right and might need a lot of fixing later.&lt;/p&gt;
&lt;p&gt;Another thing to consider with low-code is getting stuck with one vendor. If you build a lot on a specific platform, it can be really hard or expensive to move away from it because they use their own special systems or data formats. This vendor lock-in can be a form of tech debt itself. Plus, with low-code, you often don&amp;#39;t have as much control over the underlying code, which can make it harder to make things run super efficiently or to figure out really tricky bugs.&lt;/p&gt;
&lt;p&gt;Now, custom code isn&amp;#39;t immune to tech debt either. When developers are under pressure to deliver quickly, they might take shortcuts in their coding, use bad practices, or not test things properly, all of which adds to tech debt. Not having good documentation is another big source of tech debt in custom projects because it makes it much harder to maintain, update, and understand the code later. Using old technologies might seem faster now, but it can create security problems and compatibility issues later on. And if you don&amp;#39;t have consistent code reviews and don&amp;#39;t follow good coding standards, you can end up with a messy codebase that&amp;#39;s hard to work with and update, which is a lot of tech debt.&lt;/p&gt;
&lt;p&gt;Ignoring tech debt, whether it&amp;#39;s from low-code or custom code, can cause big problems. It can lead to higher costs for fixing bugs and maintaining the software, slow down future development because the code is a mess, and cause performance issues that make the software slow or unreliable. So, while low-code can be fast, it doesn&amp;#39;t automatically mean you won&amp;#39;t have tech debt. The limitations of pre-built parts and not seeing the underlying code can lead to workarounds and dependencies that can become a pain later. The ease of low-code might also tempt people to focus on speed over things like long-term maintainability and how well it will scale, which can lead to problems down the line.&lt;/p&gt;
&lt;p&gt;In custom code, the rush to finish can often lead to tech debt through quick fixes and compromises in code quality, testing, and documentation. When the main goal is just to meet deadlines, developers might choose faster, less robust solutions that solve the immediate problem but make the code more complex and inefficient in the long run. This trade-off between short-term speed and long-term maintainability is what tech debt is all about. So, managing tech debt is really important in both low-code and custom code to make sure your software stays healthy, easy to maintain, and can grow as needed. If you ignore it, you&amp;#39;ll likely see development slow down, maintenance costs go up, and performance suffer. Taking a proactive approach to find, prioritize, and fix tech debt is crucial for any software project, no matter how you build it.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Low-Code vs. Custom Code: Let&amp;#39;s Break It Down&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When you really compare low-code and custom code in terms of speed and tech debt, some key differences pop out. When it comes to speed, low-code usually wins in the beginning because you can build and deploy things much faster using those visual tools and pre-made pieces. Custom code, on the other hand, takes longer because you&amp;#39;re building everything from scratch, which means more time for planning, coding, and testing.&lt;/p&gt;
&lt;p&gt;Regarding tech debt, both can have it, but it often comes from different places. In low-code, it might be from the platform&amp;#39;s limitations, leading to workarounds or relying on specific platform features that could cause problems later. With custom code, it&amp;#39;s often about how the code is written – taking shortcuts, writing bad code, or not documenting things well, which makes the code harder to maintain.&lt;/p&gt;
&lt;p&gt;Choosing between them means thinking about the trade-offs between getting something out quickly and the long-term effects on tech debt. Going with the speed of low-code might mean less flexibility and more reliance on that platform, potentially leading to tech debt in the form of workarounds or platform limitations. On the flip side, custom code is slower at first but gives you more control, which, if you code well, can help you manage tech debt better in the long run.&lt;/p&gt;
&lt;p&gt;Cost is another thing to think about, both the initial cost of development and the ongoing cost of dealing with tech debt. Low-code might seem cheaper initially because it&amp;#39;s faster and might not need as many specialized developers, but if you rack up tech debt, maintenance could get expensive later. Custom code usually costs more upfront and takes longer, but if the code is good and tech debt is managed, it could be cheaper to maintain in the long run.&lt;/p&gt;
&lt;p&gt;So, the choice between low-code and custom code often comes down to whether you need speed right now or if you&amp;#39;re more focused on avoiding long-term tech debt and platform limitations. Faster development, no matter if it&amp;#39;s low-code or just taking shortcuts in custom code, can increase the chances of getting tech debt. When the focus is just on getting things done fast, important things like code quality, thorough testing, and good documentation might get missed, leading to a codebase that&amp;#39;s harder and more expensive to deal with later.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s why businesses really need to think about their specific project needs, their long-term plans, and what resources they have when deciding between low-code and custom code. They&amp;#39;ve got to find that right balance between how fast they need to go and how much tech debt they&amp;#39;re willing to take on. There&amp;#39;s no single right answer. It really depends on things like how complex the app is, how much customization you need, how important things like scalability and security are, and how good you are at managing tech debt over time.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Got Questions? Let&amp;#39;s Tackle Some FAQs&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To make things even clearer, let&amp;#39;s go through some common questions people have about low-code and custom code.&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What&amp;#39;s the big difference between traditional development and low-code development?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  The main difference is how much coding you have to do. Traditional development
  involves a lot of manual coding by skilled developers, while low-code uses
  visual tools and pre-built components to minimize coding, making it easier for
  more people to build apps, even if they don&amp;#39;t have a coding background.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Will low-code development take away developers&amp;#39; jobs?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Nope, low-code isn&amp;#39;t meant to replace developers. It&amp;#39;s more like a helpful
  tool that can make their jobs easier and let non-technical people help out
  with the development process. Low-code platforms can automate some of the more
  routine tasks, so developers can focus on the really complex and important
  projects.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the good and bad things about low-code development?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  On the plus side, low-code can speed up development and lower costs because
  you&amp;#39;re building apps faster with visual tools and pre-made pieces. It also
  lets people who aren&amp;#39;t coders create working apps, which is great for internal
  tools and automating processes. But, the downsides can be limited options for
  customization, getting stuck with a particular vendor, and it might not be the
  best for really complex apps.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the good and bad things about traditional development?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  The good things about traditional development are that you get highly
  customized solutions with lots of flexibility, it can scale well for long-term
  growth, it can have strong security, and it can integrate with other systems
  easily. The bad things can be higher costs upfront and for maintenance, it
  takes longer to develop, and you need developers with specific coding skills.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How is low-code development different from no-code development?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Both low-code and no-code try to make building apps simpler, but low-code
  might still need a little bit of coding knowledge for more advanced stuff,
  while no-code lets you build apps entirely with visual interfaces without
  writing any code at all.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;When should a business think about switching from low-code to custom development?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  A business might want to switch if the costs of the low-code platform go up a
  lot, if there are security risks with the platform, or if the platform&amp;#39;s
  performance starts to limit their growth. Custom development becomes more
  appealing when you need to connect deeply with other systems and when you need
  to scale beyond what the platform can handle.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does custom development help a business&amp;#39;s efficiency?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Custom development can really boost efficiency by getting rid of the need for
  workarounds that you often have with off-the-shelf or low-code solutions. It
  lets you create workflows that are exactly tailored to how your business works
  and makes sure things run smoothly by integrating deeply with your systems.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How easy is it for new developers to learn traditional vs. low-code platforms?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Low-code platforms are generally easier to pick up for new developers compared
  to traditional development, which requires learning programming languages,
  frameworks, and complex coding concepts.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How well do low-code apps scale compared to those built with traditional methods?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Apps built with traditional custom code usually offer better scalability and
  flexibility to handle more users and complexity compared to low-code apps,
  which might have limitations depending on the platform.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the main pros and cons of using no-code/low-code platforms versus custom-built software?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  No-code/low-code platforms offer faster development, lower costs, and more
  flexibility for updates. However, they can have limited features and might not
  perform as well as custom-built solutions.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Some say no-code platforms empower non-technical teams, but do developers who are used to more control get frustrated?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Generally, no, no-code/low-code platforms don&amp;#39;t cause much friction with
  traditional developers. They&amp;#39;re often seen as serving a different part of the
  software development market, and developers can often work together with
  citizen developers, using the strengths of both approaches.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How well do no-code/low-code platforms handle scaling apps compared to custom-built solutions?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  While some enterprise-level no-code/low-code solutions have gotten better at
  scaling, they often don&amp;#39;t measure up to custom-built software, especially for
  really complex and demanding apps.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;When Does Low-Code Shine? Let&amp;#39;s Look at Some Uses&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Low-code is great for a lot of practical situations where you need speed and ease of use. One big one is building &lt;strong&gt;internal tools&lt;/strong&gt;. With low-code, businesses can quickly create things like admin panels for support teams, dashboards to see data, and tools to automate internal processes. Because it&amp;#39;s easy to connect to existing databases and APIs, low-code is perfect for making those custom internal apps that help businesses run better.&lt;/p&gt;
&lt;p&gt;Another area where low-code is really useful is for &lt;strong&gt;rapid prototyping and making Minimum Viable Products (MVPs)&lt;/strong&gt;. The visual interfaces and pre-built parts let teams quickly turn ideas into working models, so they can get feedback faster and make improvements. This speed is super important for startups and companies that want to test new ideas and see if there&amp;#39;s a market for them without spending a lot of time and money.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Workflow automation&lt;/strong&gt; is another area where low-code platforms are a big help. Automating tasks that are done over and over, standardizing support requests, and creating set ways of doing projects are just some of the things low-code lets teams do to be more productive and work together better. By making processes digital that used to be manual and take a lot of time, low-code helps organizations be more efficient and make fewer mistakes.&lt;/p&gt;
&lt;p&gt;Low-code also plays a role in &lt;strong&gt;modernizing old systems&lt;/strong&gt;. Instead of completely replacing outdated systems, which can be expensive and take a long time, businesses can use low-code platforms to build new, user-friendly apps that work with the old systems or slowly replace their functions with more modern solutions. This lets them make changes gradually and minimizes disruption to their main business operations.&lt;/p&gt;
&lt;p&gt;Creating &lt;strong&gt;customer and employee portals&lt;/strong&gt; is another area where low-code offers a lot of advantages. These self-service portals can make things better for customers and employees, improve communication, and give people easy access to information and services, which ultimately makes things more efficient and satisfying. The ability to reuse interfaces and tailor features to specific user needs makes low-code platforms great for building these kinds of apps quickly and affordably.&lt;/p&gt;
&lt;p&gt;For simpler apps that are mostly about managing data, like &lt;strong&gt;basic CRUD (Create, Read, Update, Delete) applications&lt;/strong&gt;, low-code platforms provide a straightforward way to build working solutions without needing a lot of coding. These kinds of apps are common for managing internal data and can be deployed quickly using low-code.&lt;/p&gt;
&lt;p&gt;Finally, low-code platforms are being used more and more for &lt;strong&gt;data collection and analysis&lt;/strong&gt;. They have tools to build apps for gathering data from different places, creating charts and graphs, and generating reports, which helps businesses get valuable insights from their data without the complexity of traditional development. The speed and ease with which these data-focused apps can be built make low-code a powerful tool for making decisions based on data.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;When Does Custom Code Still Rule?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While low-code is great for many things, there are times when the flexibility and control of custom code development are really necessary. For &lt;strong&gt;complex applications&lt;/strong&gt; that need intricate business logic, unique algorithms, or very specialized features, custom code is often the only way to go. Low-code platforms, because they rely on pre-built components, might not give you the fine-grained control you need to implement these kinds of sophisticated features efficiently.&lt;/p&gt;
&lt;p&gt;Similarly, if a business has &lt;strong&gt;unique needs&lt;/strong&gt; that the standard components and templates in low-code platforms just can&amp;#39;t handle, then custom code development becomes essential. This is especially true when you need to connect with existing, often older, systems, as custom code lets you create specific integration logic and APIs that might not be available in low-code platforms.&lt;/p&gt;
&lt;p&gt;Applications that have &lt;strong&gt;high-security requirements&lt;/strong&gt; and deal with sensitive data often need the strong security measures and compliance protocols that you can carefully put in place with custom code development. While many low-code platforms have security features built-in, organizations with very strict security and compliance rules might prefer the detailed control over security that custom code offers.&lt;/p&gt;
&lt;p&gt;When you need &lt;strong&gt;performance optimization&lt;/strong&gt;, especially for apps that get a lot of traffic or handle a lot of data, custom code development lets you fine-tune the app&amp;#39;s performance, speed, and how it uses resources in a way that&amp;#39;s often not possible with low-code platforms. Developers can write very efficient code and optimize database queries to make sure things run well even under heavy load.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deep integrations&lt;/strong&gt; with older systems or third-party services that need very specific integration logic or custom APIs often require the flexibility of custom code development. Low-code platforms might have pre-built connectors for common systems, but for complex or unique integration needs, you&amp;#39;ll often need the custom solutions that you can create with custom code.&lt;/p&gt;
&lt;p&gt;If a project needs &lt;strong&gt;unique user interfaces and experiences&lt;/strong&gt; that go beyond what the standard templates and drag-and-drop interfaces of low-code platforms can offer, custom code gives you the freedom to design and build highly customized and branded user experiences that can make your app stand out and keep users engaged.&lt;/p&gt;
&lt;p&gt;Finally, for applications that need &lt;strong&gt;long-term scalability and the ability to evolve&lt;/strong&gt; without being limited by a specific platform, custom code development offers the most flexibility. Custom-built apps can be designed to grow significantly over time and to adapt to future technologies without the risk of being stuck with a particular vendor&amp;#39;s plans or capabilities.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Retool: A Look at Low-Code in Action&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Retool is a great example of a low-code platform that&amp;#39;s specifically designed for building internal tools efficiently. It offers a lot of benefits for organizations that want to make their internal operations smoother. One of its big strengths is its &lt;strong&gt;speed and efficiency&lt;/strong&gt;. Retool lets developers easily connect to all sorts of databases and APIs, so they don&amp;#39;t have to spend time writing a lot of code for those connections. Plus, it has a library of over 100 pre-built and customizable React components that developers can just drag and drop to create user interfaces, which really speeds up the process.&lt;/p&gt;
&lt;p&gt;While Retool is all about low-code and even no-code, it also lets you add custom code using things like SQL, JavaScript, and Python if you need to do something more complex or specific that the pre-built components can&amp;#39;t handle. This mix of approaches lets you build quickly without losing the power of custom coding when you need it.&lt;/p&gt;
&lt;p&gt;Retool also has a &lt;strong&gt;robust development environment&lt;/strong&gt; with built-in debugging tools that let developers see what&amp;#39;s going on under the hood, like stack traces and query run times. This makes it easier to find and fix problems during development. It also integrates with Git for version control, so you can track changes and collaborate with other developers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scalability and security&lt;/strong&gt; are also important for Retool. It&amp;#39;s designed to help you build internal tools that can grow as your business grows, from simple admin panels to complex partner portals. Retool has enterprise-grade security features, including things like SOC 2 Type II compliance, detailed permissions, custom Single Sign-On (SSO), and audit logs, so you can be sure your internal tools are secure. It even has a Secrets Manager to help you keep sensitive information like API keys safe.&lt;/p&gt;
&lt;p&gt;Finally, Retool helps with &lt;strong&gt;collaboration and governance&lt;/strong&gt; within organizations. It lets teams securely share data connections and queries, which makes it easier to work together and avoids doing the same work twice. For bigger organizations with lots of teams and apps, Retool offers ways to manage everything centrally, ensuring consistency and control over how internal tools are developed across the company.&lt;/p&gt;
&lt;p&gt;Retool can be used for all sorts of important internal software, like admin panels, SQL dashboards, automated workflows, and secure partner portals. By giving you a comprehensive set of tools and features, Retool helps developers create strong and scalable internal apps quickly and efficiently, while also helping to manage and potentially reduce the tech debt that can often come with internal tooling.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Finding the Right Balance: Making the Choice&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Finding the right balance between building software quickly and managing technical debt means thinking carefully about your options. When you&amp;#39;re trying to decide between low-code and custom code, there are a few key things to consider. The &lt;strong&gt;complexity of your project&lt;/strong&gt; and how much &lt;strong&gt;customization you need&lt;/strong&gt; are really important. For simpler apps with clear requirements and a need to get them out fast, low-code might be the way to go. But for more complex projects that need very specific features or unique integrations, custom code is often the better choice.&lt;/p&gt;
&lt;p&gt;You also need to weigh how important &lt;strong&gt;speed to market&lt;/strong&gt; is against the long-term effects on &lt;strong&gt;maintainability and scalability&lt;/strong&gt;. Low-code can get you there faster initially, but you need to think about whether the limitations or workarounds might lead to more tech debt and make it harder to grow or adapt later. The &lt;strong&gt;resources you have&lt;/strong&gt;, including your budget and the skills of your development team, will also play a big role. Low-code platforms might lower development costs and not require as many specialized developers, while custom code projects usually need a team with specific coding skills and might have a larger budget. And finally, the &lt;strong&gt;security and compliance needs&lt;/strong&gt; of your app are critical. Apps that handle sensitive data or are in regulated industries might need the tighter security control that custom code development offers.&lt;/p&gt;
&lt;p&gt;No matter which way you go, managing tech debt proactively is key for the long-term health of your software. In &lt;strong&gt;custom code projects&lt;/strong&gt;, this means doing code reviews to make sure the code is good and follows standards. Using automated testing helps find and fix problems early on. Keeping clear and thorough documentation makes it easier to maintain and update the code later. And it&amp;#39;s important to fix the tech debt that could really hurt the app&amp;#39;s performance or stability.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;low-code projects&lt;/strong&gt;, managing tech debt means choosing platforms that give you some flexibility and control, so you can extend what the platform can do when you need to. It&amp;#39;s also important not to rely too much on workarounds for limitations, as these can make things more complex down the road. Making the identification and fixing of tech debt a regular part of your development process, rather than something you do later, is a good strategy for both low-code and custom code. By always thinking about tech debt throughout the development process, organizations can better balance the need for speed with the need to build software that lasts and is easy to maintain.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Wrapping Up: Finding Your Sweet Spot&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In the end, deciding between the speed of low-code and the control of custom code is all about carefully considering a lot of different things. There&amp;#39;s no single right answer; it&amp;#39;s about making a strategic choice based on what your project needs, what resources you have, and what your long-term goals are. Businesses need to really think about the trade-offs between getting things done quickly and the potential for tech debt, knowing that both approaches have their own pros and cons. As software development keeps changing, with low-code becoming more and more powerful, being able to make smart decisions about the right tools and strategies will be key to success in the digital age.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What is Low-Code? Definition and Technology Overview - Appian, accessed on May 16, 2025, &lt;a href=&quot;https://appian.com/learn/topics/low-code/what-is-low-code&quot;&gt;https://appian.com/learn/topics/low-code/what-is-low-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Low-Code Development? | Mendix, accessed on May 16, 2025, &lt;a href=&quot;https://www.mendix.com/low-code-guide/&quot;&gt;https://www.mendix.com/low-code-guide/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Is Low-Code? | IBM, accessed on May 16, 2025, &lt;a href=&quot;https://www.ibm.com/think/topics/low-code&quot;&gt;https://www.ibm.com/think/topics/low-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Low-Code Development: A Complete Guide for 2025 - Kissflow, accessed on May 16, 2025, &lt;a href=&quot;https://kissflow.com/low-code/low-code-overview/&quot;&gt;https://kissflow.com/low-code/low-code-overview/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gartner forecast: Use of low-code technologies continues to boom. - Ninox, accessed on May 16, 2025, &lt;a href=&quot;https://ninox.com/en/blog/gartner-forecast-use-of-low-code-technologies-continues-to-boom&quot;&gt;https://ninox.com/en/blog/gartner-forecast-use-of-low-code-technologies-continues-to-boom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Low Code vs. Traditional Development - Who Wins? - Topflight Apps, accessed on May 16, 2025, &lt;a href=&quot;https://topflightapps.com/ideas/no-code-low-code-vs-traditional-development/&quot;&gt;https://topflightapps.com/ideas/no-code-low-code-vs-traditional-development/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Low-Code vs Custom Development: Pros, Cons &amp;amp; Use Cases | MinovaEdge, accessed on May 16, 2025, &lt;a href=&quot;https://www.minovateck.com/low-code-vs-custom-development-pros-cons-and-use-cases&quot;&gt;https://www.minovateck.com/low-code-vs-custom-development-pros-cons-and-use-cases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Low-Code vs. Custom Development – The Best for Business in 2025 - FullStack Labs, accessed on May 16, 2025, &lt;a href=&quot;https://www.fullstack.com/labs/resources/blog/low-code-vs-custom-development-whats-best-for-business-in-2025&quot;&gt;https://www.fullstack.com/labs/resources/blog/low-code-vs-custom-development-whats-best-for-business-in-2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Navigating Custom Dev vs. Low-Code: Features, Costs, Speed - Infopulse, accessed on May 16, 2025, &lt;a href=&quot;https://www.infopulse.com/blog/custom-development-vs-low-code&quot;&gt;https://www.infopulse.com/blog/custom-development-vs-low-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Custom Software Development? | GeeksforGeeks, accessed on May 16, 2025, &lt;a href=&quot;https://www.geeksforgeeks.org/what-is-custom-software-development/&quot;&gt;https://www.geeksforgeeks.org/what-is-custom-software-development/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Retool | A better way to build custom software, accessed on May 16, 2025, &lt;a href=&quot;https://retool.com/&quot;&gt;https://retool.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Managing tech debt in a fast-paced development environment - Statsig, accessed on May 16, 2025, &lt;a href=&quot;https://www.statsig.com/perspectives/managing-tech-debt-in-a-fast-paced-development-environment&quot;&gt;https://www.statsig.com/perspectives/managing-tech-debt-in-a-fast-paced-development-environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Exploring Technical Debt: How to Manage and Reduce It - OutSystems, accessed on May 16, 2025, &lt;a href=&quot;https://www.outsystems.com/digital-transformation/tech-debt-explained-and-ways-to-reduce/&quot;&gt;https://www.outsystems.com/digital-transformation/tech-debt-explained-and-ways-to-reduce/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;9 Practical Low-Code Automation Use Cases &amp;amp; Examples - Pulpstream, accessed on May 16, 2025, &lt;a href=&quot;https://pulpstream.com/resources/blog/low-code-automation&quot;&gt;https://pulpstream.com/resources/blog/low-code-automation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is your experience with low code development platforms? : r/EnterpriseArchitect - Reddit, accessed on May 16, 2025, &lt;a href=&quot;https://www.reddit.com/r/EnterpriseArchitect/comments/1fq8bqu/what_is_your_experience_with_low_code_development/&quot;&gt;https://www.reddit.com/r/EnterpriseArchitect/comments/1fq8bqu/what_is_your_experience_with_low_code_development/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Low-Code</category><category>Custom Code</category><category>Technical Debt</category><category>Internal Tools</category><category>Software Development</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0083-low-code-vs-custom-code-speed-tech-debt/hero.jpg" length="0" type="image/jpeg"/></item><item><title>AIOps: Making DevOps Even Better with Smart AI Tools</title><link>https://mkabumattar.com/blog/post/aiops-enhancing-devops-with-ai/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/aiops-enhancing-devops-with-ai/</guid><description>Learn how AIOps is transforming DevOps with AI-driven automation, predictive analytics, and intelligent incident management. Explore key tools, benefits, and practical guidance for modern IT operations.</description><pubDate>Sat, 14 Jun 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You know how things in the tech world keep getting more complicated? Well, managing all that IT stuff can be a real headache. DevOps has been a game-changer for making software development and deployment smoother, but with everything getting so big and moving so fast, can it really keep up? That&amp;#39;s where Artificial Intelligence for IT Operations, or AIOps, comes into play. Think of it as giving DevOps a super-smart brain. By using AI, AIOps brings a whole new level of smartness and efficiency to how DevOps works, helping with things like too many alerts, fixing problems faster, and keeping systems running smoothly without you even having to ask.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;So, What&amp;#39;s AIOps All About, and Why Should DevOps Teams Care?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;AIOps is basically the next step in managing IT. Gartner came up with the term back in 2017, and it&amp;#39;s all about using machine learning to look at tons of data to automate and manage IT operations. That means using smart algorithms to handle all the complicated stuff in IT. Gartner also says that an AIOps platform uses big data and machine learning to automatically handle important IT tasks. These tasks include figuring out how different system events are related, spotting when something isn&amp;#39;t acting normal, and finding out why problems are happening in the first place.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s interesting to see how the name itself has changed. Back in 2016, people were calling it &amp;quot;Algorithmic IT Operations,&amp;quot; but the switch to &amp;quot;Artificial Intelligence for IT Operations&amp;quot; just a year later shows that folks realized AI, including machine learning, could do even more to solve the tricky problems in DevOps. This change highlights a growing understanding of how AI can go beyond just simple algorithms and offer more advanced solutions for how we build and release software today.&lt;/p&gt;
&lt;p&gt;For DevOps teams, AIOps is like having a powerful set of tools to deal with the growing complexity and huge amounts of data that come with today&amp;#39;s IT environments. The main thing it does is make things more reliable and available, which ultimately saves money and speeds up digital transformation. Plus, AIOps helps DevOps teams by giving them smart, useful insights that lead to more automation and better teamwork between the development and operations sides. You&amp;#39;ll notice that automation keeps popping up in different definitions and that&amp;#39;s because it&amp;#39;s a key part of making DevOps better. AIOps isn&amp;#39;t just about looking at data; it&amp;#39;s about using what you learn to automatically fix things and make workflows smoother, which is exactly what DevOps is all about – faster and more dependable software delivery through automation.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How Does AI Make DevOps Smarter?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;AI doesn&amp;#39;t just fit into one part of DevOps; it makes the whole process smarter, from beginning to end.&lt;/p&gt;
&lt;p&gt;When you&amp;#39;re &lt;strong&gt;planning&lt;/strong&gt;, AI can look at old data and trends to guess what resources you&amp;#39;ll need in the future and where problems might pop up, helping you make better decisions. While you&amp;#39;re &lt;strong&gt;coding&lt;/strong&gt;, AI-powered tools can give you suggestions as you type, find potential bugs early on, and make sure your code is good overall, which really helps developers work more efficiently. The &lt;strong&gt;building&lt;/strong&gt; phase gets a boost from AI&amp;#39;s ability to make build processes better, predict when builds might fail, and automate the whole build management thing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Testing&lt;/strong&gt; is another area where AI makes a big difference. It can automatically create test cases, decide which tests are most important based on risk, and analyze test results to give feedback to developers faster, making the testing process more efficient and thorough. When it&amp;#39;s time for &lt;strong&gt;releasing&lt;/strong&gt;, AI can predict how likely the deployment is to succeed, spot potential issues before they happen, and even automatically roll things back if something goes wrong after deployment. The &lt;strong&gt;deployment&lt;/strong&gt; phase sees AI making deployment schedules better, automating deployment pipelines, and making sure deployments are smooth and consistent across different environments.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;operating&lt;/strong&gt; phase gets a big upgrade with AI-driven monitoring tools. These tools constantly learn how your system behaves, spot unusual activity in real time, and give you smart alerts, so you can fix problems before they affect users. Finally, in the &lt;strong&gt;monitoring&lt;/strong&gt; phase, AI can look at tons of monitoring data, connect events that might seem unrelated, and figure out the real reasons behind incidents much faster and more accurately than if you were doing it all by hand.&lt;/p&gt;
&lt;p&gt;Basically, AI&amp;#39;s involvement in every part of the DevOps process is a big shift from just reacting to problems and manually fixing them to actually predicting issues and automatically taking care of them. This not only makes the software development and delivery process smoother but also makes it more reliable and faster, which ultimately leads to happier customers.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;DevOps Phase&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AI Application&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Snippet ID(s)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Planning&lt;/td&gt;
&lt;td&gt;Predict resource needs, identify bottlenecks&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coding&lt;/td&gt;
&lt;td&gt;Code suggestions, bug identification, quality assurance&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Building&lt;/td&gt;
&lt;td&gt;Optimize build processes, predict failures, automate management&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing&lt;/td&gt;
&lt;td&gt;Automate test case generation, prioritize tests, analyze results&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Releasing&lt;/td&gt;
&lt;td&gt;Predict deployment success, identify issues, automate rollback&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deploying&lt;/td&gt;
&lt;td&gt;Optimize schedules, automate pipelines, ensure consistency&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating&lt;/td&gt;
&lt;td&gt;Real-time anomaly detection, intelligent alerts, proactive resolution&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring&lt;/td&gt;
&lt;td&gt;Analyze data, correlate events, identify root causes&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Can AIOps Really See What&amp;#39;s Coming? The Power of Predicting Problems.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;One of the coolest things AIOps can do is predict when problems are going to happen before they actually do. By using machine learning, AIOps can look at patterns and unusual activity in both past and current data to guess when things might go wrong. This lets DevOps teams take action early, like putting in patches or fixing potential errors, before they cause trouble for users, which makes the whole system much more reliable. AI algorithms can go through tons of data, like server logs and past trends, to find patterns that might mean a problem is on its way, allowing teams to take steps to prevent it. Predictive analytics can even see potential failures and let teams know, so they can step in before anything bad happens. The power of AI is in its ability to use system data for real-time analysis, finding small changes, patterns, and connections that can be used to understand what&amp;#39;s normal and what&amp;#39;s not, so it can accurately spot unusual activity and predict problems.&lt;/p&gt;
&lt;p&gt;Think about how this works in the real world. Netflix, for example, uses AI to watch its huge streaming system, predicting potential outages or performance issues before they even occur. Similarly, AI can look at old incident data along with current system information to pinpoint which parts are most likely to fail, helping teams focus their maintenance efforts where they&amp;#39;re needed most. AI can even keep an eye on things like how much of a server&amp;#39;s CPU is being used and predict when it might get too high, automatically taking action to add more resources before performance suffers. This ability to see problems coming is a big step up from old monitoring systems that mostly just react after something has already gone wrong. This proactive approach can really cut down on downtime, make users happier, and save organizations a lot of money by preventing service disruptions.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;More Than Just Basic Scripts: How AIOps Makes Automation Super Smart for DevOps.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Automation is a key part of DevOps, but AIOps takes it to a whole new level by making it intelligent, thanks to the power of AI and machine learning. While regular DevOps automation often involves writing scripts for routine tasks, AIOps can automate more complex things, like figuring out the root cause of problems, sorting incidents, and even automatically fixing them. AIOps can automatically fix issues by intelligently recognizing and categorizing IT events, and then triggering actions to resolve them without any human help. AI-powered bots can handle repetitive tasks like testing code, deploying it, and monitoring systems, which really cuts down on manual work and speeds up the whole development process. Plus, AI powers systems that can heal themselves, automatically finding and fixing issues as they happen, often without needing anyone to step in.&lt;/p&gt;
&lt;p&gt;This advanced automation has some big benefits, including a significant decrease in the time it takes to resolve issues (MTTR), better overall efficiency, and the important ability to free up DevOps teams to work on more strategic and innovative projects. AIOps plays a big role in reducing MTTR by helping IT Operations find, investigate, and fix problems much faster than traditional methods. Automating the process of checking and fixing things makes issue resolution smoother, reduces errors, and further improves MTTR. AIOps can even automate the ticketing process while making sure the Configuration Management Database (CMDB) stays up-to-date. AIOps makes automation in DevOps smarter. Regular DevOps automation usually relies on pre-written scripts and rules. However, AIOps can learn from past incidents and data patterns to make better decisions about what to automate and how to respond to different situations. This leads to a more flexible and efficient automation approach that can handle a wider range of problems with less human intervention.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Splunk and Moogsoft: Big Names in the AIOps and DevOps World.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When it comes to AIOps tools that really boost DevOps practices, Splunk and Moogsoft are two of the big players. Splunk is well-known as a leader in IT Operations Management (ITOM) and offers a comprehensive AIOps solution. This solution effectively connects and applies machine learning to a huge amount of data, giving DevOps teams real-time, predictive performance monitoring and integrated IT management workflows. Splunk AIOps uses machine learning to automatically handle important tasks like spotting unusual activity and connecting related events, analyzing tons of network and system data to find the underlying causes of problems. Specifically, Splunk IT Service Intelligence (ITSI) is designed as an AIOps solution to help DevOps teams get the most out of AIOps, providing real-time, predictive performance insights and smoother IT management workflows. Additionally, Splunk uses machine learning for broader operational intelligence, enabling predictive analytics for deployment data and also for automated security analysis within the DevOps process.&lt;/p&gt;
&lt;p&gt;Moogsoft, on the other hand, is recognized as a pioneer and a leading provider in the AIOps space, offering a cloud-based platform specifically designed for DevOps and Site Reliability Engineering (SRE) teams. Moogsoft AIOps is great at reducing unnecessary alerts, effectively connecting related alerts, and providing strong built-in monitoring capabilities, including collecting lots of metrics and using advanced methods to detect unusual activity, all of which helps DevOps teams resolve incidents faster. The Moogsoft platform is powered by its own AI and machine learning algorithms, giving DevOps teams complete visibility into potentially critical incidents and allowing them to address these issues quickly and proactively. Moogsoft APEX AIOps Incident Management further shows this by offering an advanced AI-driven platform that helps software engineers, developers, and operations teams quickly understand their systems, identify problems, and fix them more efficiently.&lt;/p&gt;
&lt;p&gt;Both Splunk and Moogsoft work smoothly with existing DevOps workflows to significantly improve monitoring, incident management, and automation capabilities. These platforms can take in data from a wide variety of DevOps tools and platforms, providing a central and complete view of overall system health and performance. Their built-in AI capabilities enable smart alerting, which is really important for reducing the often overwhelming number of alerts and allowing DevOps teams to focus on the most critical issues that need their attention. Moreover, both platforms help with faster and more accurate root cause analysis and automatically respond to common and recurring incidents, thereby improving the overall stability and resilience of the entire system. The presence and advanced features of platforms like Splunk and Moogsoft clearly show how AIOps principles are being put into practice within the DevOps environment. These tools offer real solutions to the complex challenges of managing modern IT environments by effectively using AI for intelligent monitoring, prediction, and automation, making them invaluable for DevOps teams striving for better efficiency and reliability.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Got Questions? Common Queries About AIOps in DevOps.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;As organizations think about bringing AIOps into their DevOps practices, some common questions often come up. Understanding these key points is important for making it work well.&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What&amp;#39;s the main difference between DevOps and AIOps?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  DevOps is all about bringing together and automating the processes between
  software development and IT operations to speed up software delivery. AIOps,
  on the other hand, focuses on using AI and machine learning to automate and
  improve IT operations, especially in areas like monitoring, data analysis, and
  incident management. It often works alongside DevOps practices to make the
  operational parts of the software lifecycle better.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does AIOps help with the alert overload that often happens in DevOps?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  AIOps uses smart filters and advanced techniques to connect related events,
  which really helps reduce the noise and overwhelming number of alerts that
  DevOps teams often face. By looking at how different events are related and
  intelligently figuring out which alerts are false alarms, AIOps makes sure
  that teams are only alerted to the really important issues, allowing them to
  focus their attention and resources where they&amp;#39;re most needed.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some common challenges when trying to implement AIOps in a DevOps environment?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Getting AIOps to work isn&amp;#39;t always easy. One big thing is making sure you have
  good data from your entire IT infrastructure. People might also worry about IT
  teams losing their jobs. It&amp;#39;s also important to find the right balance between
  automation and human oversight, deal with any cultural changes within teams,
  and have realistic expectations about what AIOps can do.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can organizations get started with AIOps for DevOps?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Organizations can start by really looking at their current IT setup, figuring
  out where their biggest problems are, and clearly defining what they want to
  achieve with AIOps. Choosing the right AIOps platform that works well with
  their existing systems and processes is crucial. It&amp;#39;s usually a good idea to
  create a solid plan, start with a small test project, and then gradually
  expand the solution across the organization.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;Is AIOps meant to replace DevOps engineers?&quot;&gt;
  No, AIOps isn&apos;t meant to replace DevOps engineers. Instead, it&apos;s designed to
  help them do their jobs better. By automating routine and less interesting
  tasks and providing smart insights from data analysis, AIOps allows engineers
  to focus on more strategic, innovative, and complex work that requires their
  special skills.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What kind of data does AIOps need to be effective in a DevOps setting?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  For AIOps to really work well in a DevOps environment, it needs to have access
  to a lot of data from the entire IT landscape. This includes logs, performance
  metrics, various system events, and traces collected from infrastructure
  components, applications, and existing monitoring systems.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;Addressing these common questions gives a better understanding of how AIOps and DevOps relate, the real benefits and potential challenges of using AIOps, and practical advice on how organizations can start using intelligent IT operations.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;The Smart Future: What&amp;#39;s Next for AIOps and DevOps?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Looking ahead, the connection between AIOps and DevOps is likely to become even stronger and more advanced. We&amp;#39;ll probably see more and more automation, handling even more complex tasks, and IT systems might even start to heal themselves. Improvements in AI and machine learning will make predicting problems and figuring out their root causes even more accurate and effective, leading to even more proactive issue resolution. New trends like Generative AI also have the potential to really impact AIOps and DevOps, possibly automating tasks like writing code, creating documentation, and even helping with incident response. A key part of this future will be a greater focus on making AIOps customer-centric. The goal will be not just to make systems more efficient and reliable but also to actively improve the experience for end-users and ultimately drive better business results through smart insights and automated actions.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;In Conclusion: Get Ready for the Intelligence Revolution in Your DevOps Practices.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Bringing AIOps together with DevOps is a powerful step forward in how organizations manage their software development and delivery. By using the intelligence of AI, DevOps teams can see big improvements in how efficiently, reliably, and quickly they work. AIOps helps with major issues like alert overload and slow problem-solving, while also enabling proactive prediction of incidents and advanced automation. As shown by leading platforms like Splunk and Moogsoft, AIOps isn&amp;#39;t just a concept; it&amp;#39;s a real thing that&amp;#39;s changing IT operations. Organizations should definitely look into the potential of AIOps tools to enhance their DevOps practices and move towards a smarter and more efficient future for IT operations.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What Is AIOps? Artificial Intelligence for IT Operations - Pure Storage, accessed on May 16, 2025, &lt;a href=&quot;https://www.purestorage.com/au/knowledge/what-is-aiops.html&quot;&gt;https://www.purestorage.com/au/knowledge/what-is-aiops.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Definition of AIOps (Artificial Intelligence for IT Operations) - IT Glossary | Gartner, accessed on May 16, 2025, &lt;a href=&quot;https://www.gartner.com/en/information-technology/glossary/aiops-artificial-intelligence-operations&quot;&gt;https://www.gartner.com/en/information-technology/glossary/aiops-artificial-intelligence-operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Is AIOps (Artificial Intelligence for IT Operations)? - Datadog, accessed on May 16, 2025, &lt;a href=&quot;https://www.datadoghq.com/knowledge-center/aiops/&quot;&gt;https://www.datadoghq.com/knowledge-center/aiops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is AIOps? A Comprehensive AIOps Intro - Splunk, accessed on May 16, 2025, &lt;a href=&quot;https://www.splunk.com/en_us/blog/learn/aiops.html&quot;&gt;https://www.splunk.com/en_us/blog/learn/aiops.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AIOps for ITOps, DevOps, &amp;amp; SRE Teams | Moogsoft AIOps Guide, accessed on May 16, 2025, &lt;a href=&quot;https://www.moogsoft.com/everything-aiops-guide/&quot;&gt;https://www.moogsoft.com/everything-aiops-guide/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AI in DevOps: Software Testing with Intelligent Automation - ACCELQ, accessed on May 16, 2025, &lt;a href=&quot;https://www.accelq.com/blog/ai-in-devops/&quot;&gt;https://www.accelq.com/blog/ai-in-devops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Role of AI in DevOps - GitLab, accessed on May 16, 2025, &lt;a href=&quot;https://about.gitlab.com/topics/devops/the-role-of-ai-in-devops/&quot;&gt;https://about.gitlab.com/topics/devops/the-role-of-ai-in-devops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Power DevOps Teams with AIOps | Observability for CI/CD Cycles - Moogsoft, accessed on May 16, 2025, &lt;a href=&quot;https://www.moogsoft.com/solutions/devops/&quot;&gt;https://www.moogsoft.com/solutions/devops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Modern IT Management With AIOps | Splunk, accessed on May 16, 2025, &lt;a href=&quot;https://www.splunk.com/en_us/form/modern-it-management-with-aiops.html&quot;&gt;https://www.splunk.com/en_us/form/modern-it-management-with-aiops.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AIOps vs. Traditional DevOps: Which One Delivers Better Efficiency? - Algoworks, accessed on May 16, 2025, &lt;a href=&quot;https://www.algoworks.com/blog/aiops-vs-devops-efficiency-comparison/&quot;&gt;https://www.algoworks.com/blog/aiops-vs-devops-efficiency-comparison/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Integrate AIOps in DevOps? - XenonStack, accessed on May 16, 2025, &lt;a href=&quot;https://www.xenonstack.com/blog/integrate-aiops-devops&quot;&gt;https://www.xenonstack.com/blog/integrate-aiops-devops&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AIOps: Artificial Intelligence for IT Operations - ScienceLogic, accessed on May 16, 2025, &lt;a href=&quot;https://sciencelogic.com/product/resources/what-is-aiops&quot;&gt;https://sciencelogic.com/product/resources/what-is-aiops&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How AIOps Empowers DevOps Teams &amp;amp; Improves Workflows - Motadata, accessed on May 16, 2025, &lt;a href=&quot;https://www.motadata.com/blog/aiops-for-devops/&quot;&gt;https://www.motadata.com/blog/aiops-for-devops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AIOps: The Future of DevOps | PagerDuty, accessed on May 16, 2025, &lt;a href=&quot;https://www.pagerduty.com/blog/aiops-future-of-devops/&quot;&gt;https://www.pagerduty.com/blog/aiops-future-of-devops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Observability for DevOps and SREs - Moogsoft, accessed on May 16, 2025, &lt;a href=&quot;https://www.moogsoft.com/wp-content/uploads/2020/10/Moogosft-Solution-Brief-100120.pdf&quot;&gt;https://www.moogsoft.com/wp-content/uploads/2020/10/Moogosft-Solution-Brief-100120.pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AIOps</category><category>DevOps</category><category>AI</category><category>Automation</category><category>Observability</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0082-aiops-enhancing-devops-with-ai/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Centralized Logging with Loki, Grafana, and Fluent Bit: Making Sense of Your Systems</title><link>https://mkabumattar.com/blog/post/centralized-logging-loki-grafana-fluent-bit/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/centralized-logging-loki-grafana-fluent-bit/</guid><description>Learn how to set up centralized logging with Loki, Grafana, and Fluent Bit for Kubernetes and microservices. This comprehensive guide covers deployment, configuration, and troubleshooting for a robust observability solution.</description><pubDate>Sat, 07 Jun 2025 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;strong&gt;Why Centralized Logging is Your First Step to Understanding Your Systems?&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What exactly is centralized logging and why should you care?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Think of your IT setup as a busy city. Lots of things are happening at once across different buildings, roads, and networks. Centralized logging is like having a single control room where all the important information from this city – from the traffic flow to the power usage in buildings – gets collected in one place. This makes it way easier for the city managers (that&amp;#39;s you and your team) to see what&amp;#39;s going on, spot any problems, and fix them quickly.&lt;/p&gt;
&lt;p&gt;In today&amp;#39;s world, our tech systems are becoming more spread out, especially with things like microservices and cloud setups. Imagine trying to keep track of everything if the logs were scattered all over the place, like trying to find a single lost sock in a huge laundry pile. Centralized logging brings all that information together, helping you keep things under control and understand what&amp;#39;s happening in your digital world.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Let&amp;#39;s talk benefits: easier fixes, better security, and staying out of trouble (compliance).&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Getting all your logs in one spot has a ton of perks that make your IT life easier and your organization safer. One of the biggest wins is &lt;strong&gt;fixing problems faster&lt;/strong&gt;. When all the information about what&amp;#39;s happening in your systems is in one place, it&amp;#39;s much quicker to figure out what went wrong when something breaks. Instead of hunting through logs on different servers, you can just look in one central location. This means less downtime and happier users.&lt;/p&gt;
&lt;p&gt;Centralized logging also seriously &lt;strong&gt;boosts your security&lt;/strong&gt;. By having all your system, application, and security records together, your security team can get a much clearer picture of your organization&amp;#39;s defenses. This helps them spot anything unusual, figure out if there&amp;#39;s been a security breach, and investigate any incidents thoroughly. Being able to connect events from different systems, which is much simpler with centralized logs, is key to understanding the full impact of security threats.&lt;/p&gt;
&lt;p&gt;Beyond just making things run smoother and keeping things secure, centralized logging also helps you &lt;strong&gt;stay compliant with regulations&lt;/strong&gt;. Many industries have rules that say you need to keep detailed records of your IT systems for audits. Centralized logging makes this easier by giving you the tools to watch, analyze, and respond to security-related events. These systems often include features to keep your data safe, control who can see it, and create reports to show you&amp;#39;re following the rules. Plus, you can set up consistent rules for how long you keep your data, making sure you meet all the legal requirements.&lt;/p&gt;
&lt;p&gt;But wait, there&amp;#39;s more! Centralized logging also helps you &lt;strong&gt;organize&lt;/strong&gt; your log data into a consistent format, &lt;strong&gt;add extra helpful information&lt;/strong&gt; to your logs, &lt;strong&gt;connect related events&lt;/strong&gt; from different systems, &lt;strong&gt;search through your logs quickly and easily&lt;/strong&gt;, &lt;strong&gt;handle more and more logs as you grow&lt;/strong&gt;, and &lt;strong&gt;keep old logs&lt;/strong&gt; for future analysis. Basically, it simplifies managing your logs, saves you money on different logging tools, and frees up your IT team to work on more important things.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Why is centralized logging a game-changer for Kubernetes and microservices?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The way we build applications has changed a lot with &lt;strong&gt;microservices&lt;/strong&gt;. Instead of one big application, we now have lots of smaller, independent pieces that work together. This is great for making things scale and be more flexible. But it also means things can get complicated, especially when it comes to keeping an eye on everything and figuring out what&amp;#39;s going wrong. In these setups, centralized logging isn&amp;#39;t just a good idea; it&amp;#39;s essential for seeing what&amp;#39;s happening. You really need good logging to figure out problems that might be happening across several different services.&lt;/p&gt;
&lt;p&gt;Similarly, &lt;strong&gt;Kubernetes&lt;/strong&gt;, which helps manage all these containers, is also very dynamic and spread out. It manages lots of machines, and each machine might be running many containers that can start, stop, and move around at any time. The logs from these short-lived containers can disappear once the container or the pod it&amp;#39;s in is gone. This makes it super important to have a central place to store these logs in Kubernetes so you can always go back and look at them if you need to troubleshoot.&lt;/p&gt;
&lt;p&gt;Centralized logging gives you &lt;strong&gt;one place to see all the logs&lt;/strong&gt; coming from all those different microservices that make up your modern application. This makes it much easier to see how your application is doing overall and to find problems that might be affecting multiple services. Without this central view, trying to figure out issues in a microservices world can feel like trying to find a needle in a haystack that&amp;#39;s spread across many different places.&lt;/p&gt;
&lt;p&gt;One of the toughest things about debugging microservices is &lt;strong&gt;following a single request&lt;/strong&gt; as it goes through a chain of different services. Centralized logging, especially when you use special IDs to track each request, makes this much simpler. By adding the same tracking ID to logs from different services, you can follow the entire journey of a request, making it much easier to pinpoint exactly where things went wrong or where there&amp;#39;s a slowdown. This kind of tracking is often really hard to do effectively without a centralized logging system.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;The Power Trio: Loki, Grafana, and Fluent Bit Explained&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What makes Loki a compelling &amp;quot;ELK alternative&amp;quot; for log collection?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Grafana Loki has become a really popular tool for collecting logs, especially if you&amp;#39;re working with cloud-based systems. It&amp;#39;s inspired by Prometheus, which is great for tracking metrics, and it&amp;#39;s designed to handle lots of logs, be reliable, and work well for different teams or applications at the same time.&lt;/p&gt;
&lt;p&gt;One of the main things that makes Loki different from the traditional ELK (Elasticsearch, Logstash, Kibana) setup is how it handles indexing. Instead of indexing every single word in your logs like ELK does, Loki takes a simpler approach. It only indexes some extra information about the logs, called labels. These labels are like tags you can add to your logs, such as the application name or the server it came from. A log stream in Loki is just a series of logs that all have the same set of labels. This simpler indexing method makes Loki easier to run and can save you money, especially compared to how much resources ELK can use.&lt;/p&gt;
&lt;p&gt;Loki stores your actual log data by compressing it into chunks and saving these chunks in a storage system. This could be something like Amazon S3, Google Cloud Storage, or even just a local hard drive if you&amp;#39;re testing things out. By using these kinds of storage systems, Loki gets the benefits of being reliable, scalable, and cost-effective.&lt;/p&gt;
&lt;p&gt;To let you search and analyze your logs, Loki uses a query language called LogQL. If you&amp;#39;re already familiar with Prometheus&amp;#39;s query language, PromQL, you&amp;#39;ll find LogQL pretty easy to pick up. LogQL lets you filter your logs based on those labels and also do basic text searches within the log messages themselves.&lt;/p&gt;
&lt;p&gt;Loki is especially good at managing logs from Kubernetes, which is a system for running containers. It can automatically find and index information about these containers, like their labels, which can be really helpful when you&amp;#39;re trying to figure out what&amp;#39;s going on in your containerized environment.&lt;/p&gt;
&lt;p&gt;So, Loki&amp;#39;s label-based indexing offers a good alternative to ELK&amp;#39;s full-text indexing. It can be cheaper and simpler to run, especially if you&amp;#39;re using cloud services where costs matter. However, it&amp;#39;s worth noting that because it doesn&amp;#39;t index everything, Loki might not be the best choice if you need to do very complex text searches across all your logs. If you&amp;#39;re already using Prometheus for metrics, Loki can be a natural fit for your logging needs.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How does Grafana turn raw logs into useful insights and visuals?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Grafana is a key tool in the world of monitoring. It&amp;#39;s a free and open-source application that lets you analyze and visualize data from many different sources, including metrics, logs, and traces. It takes all that raw data and turns it into easy-to-understand charts, graphs, and alerts.&lt;/p&gt;
&lt;p&gt;One of Grafana&amp;#39;s strengths is how well it works with Loki. Grafana has built-in support for Loki as a data source, which means you can easily use Grafana to query and see the logs you&amp;#39;ve stored in Loki using Loki&amp;#39;s own query language, LogQL. This close connection is super important for getting a full picture of your systems because it lets you see your logs alongside other information, like metrics from Prometheus and traces from systems like Jaeger or Tempo, all in one place.&lt;/p&gt;
&lt;p&gt;Grafana gives you lots of tools to help you make sense of your raw logs. The &lt;strong&gt;Explore&lt;/strong&gt; view is great for when you want to just dive in and search through your logs. You can pick your Loki data source and then use label filters or type in LogQL queries to find the logs you&amp;#39;re looking for and examine individual log entries. This interactive way of exploring your logs is really helpful for figuring out problems and understanding how your systems are behaving in real-time.&lt;/p&gt;
&lt;p&gt;If you want to create more permanent and shareable views of your log data, Grafana&amp;#39;s &lt;strong&gt;Dashboards&lt;/strong&gt; are the way to go. You can build custom dashboards with different panels that show trends in your logs, error rates, and other important information you get from your logs using LogQL. The &lt;strong&gt;Logs&lt;/strong&gt; panel specifically lets you see the raw log lines and gives you options to filter, sort, and highlight them, making it easier to spot patterns and issues. The Grafana community also shares lots of pre-built dashboards for Loki that you can use and customize.&lt;/p&gt;
&lt;p&gt;On top of that, Grafana&amp;#39;s &lt;strong&gt;Alerting&lt;/strong&gt; system lets you set up rules based on LogQL queries. This means you can get notified if certain log patterns appear or if certain thresholds are reached. You can get these alerts through various channels like email, Slack, or PagerDuty. This helps you catch and fix potential problems before they cause bigger issues for your users.&lt;/p&gt;
&lt;p&gt;Basically, Grafana is like the visual brain for Loki, taking all that unstructured log data and turning it into meaningful visuals and actionable insights. Its integration with Loki completes the picture by letting you connect your logs with metrics and traces, giving you a full understanding of how healthy and performant your systems are.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Why is Fluent Bit the go-to lightweight log processor and forwarder for cloud setups?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In the fast-paced and resource-conscious world of cloud computing, especially when you&amp;#39;re using containers with Kubernetes, you need a log processor and forwarder that&amp;#39;s both efficient and reliable. Fluent Bit has become a top choice here. It&amp;#39;s known for being fast, lightweight, and having lots of capabilities.&lt;/p&gt;
&lt;p&gt;Fluent Bit&amp;#39;s main job is to collect log data from different places, like your applications, systems, and even metrics. It then puts this data into a consistent format and sends it off to one or more destinations where it can be stored and analyzed. It works really well with Docker and Kubernetes, which is a big reason why so many people in the cloud world use it. In Kubernetes, Fluent Bit is often set up as a &lt;code&gt;DaemonSet&lt;/code&gt;, which means it runs on every machine in your cluster, making sure it collects logs from all your running containers.&lt;/p&gt;
&lt;p&gt;One of Fluent Bit&amp;#39;s key advantages is its &lt;strong&gt;lightweight design&lt;/strong&gt;. It&amp;#39;s written in C, which makes it much smaller and use fewer resources compared to other log processors like Fluentd. This efficiency is really important in environments like Kubernetes where how much resources you use directly affects costs and performance, especially when you have lots of containers running.&lt;/p&gt;
&lt;p&gt;Fluent Bit&amp;#39;s functionality can be easily expanded thanks to its wide range of &lt;strong&gt;input, filter, and output plugins&lt;/strong&gt;. Input plugins let it collect data from various sources like files, system logs, and network connections. Filter plugins allow you to process and add information to the data, for example, by adding Kubernetes-specific details or making sense of log lines. Output plugins handle sending the processed data to different places, including logging systems like Loki, Elasticsearch, Splunk, and cloud monitoring services. Fluent Bit has special plugins for working with Kubernetes that automatically add information about your containers, like their names and locations and it also has specific output plugins for sending logs directly to Loki.&lt;/p&gt;
&lt;p&gt;Plus, Fluent Bit &lt;strong&gt;works with any vendor&lt;/strong&gt;, meaning it&amp;#39;s not tied to a specific logging system or cloud provider. This gives you the freedom to choose the tools that work best for you without being locked into one particular ecosystem. You can even configure Fluent Bit to send data to multiple places at the same time.&lt;/p&gt;
&lt;p&gt;In short, Fluent Bit&amp;#39;s combination of being lightweight, having lots of features through its plugins, working great with Kubernetes, and not being tied to any specific vendor makes it an excellent choice for collecting and sending logs in the dynamic and resource-sensitive world of cloud setups.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Fluent Bit in Action: Collecting Logs from Your Kubernetes Clusters&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;How do you deploy Fluent Bit as a &lt;code&gt;DaemonSet&lt;/code&gt; in Kubernetes?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To make sure you&amp;#39;re getting logs from every corner of your Kubernetes setup – every machine and every container – the best way to run Fluent Bit is as a &lt;code&gt;DaemonSet&lt;/code&gt;. Think of a &lt;code&gt;DaemonSet&lt;/code&gt; as a way to make sure a specific helper program (in this case, Fluent Bit) is running on all (or some) of your machines in the cluster. This is super important for collecting all your logs because Kubernetes is always changing – containers can start, stop, and move around.&lt;/p&gt;
&lt;p&gt;The easiest and often recommended way to get Fluent Bit running as a &lt;code&gt;DaemonSet&lt;/code&gt; in Kubernetes is by using the official Helm Chart provided by the Fluent project. Helm is like a package manager for Kubernetes, making it simpler to install and manage applications. To use the Helm chart, you first need to tell Helm where to find the Fluent charts, and then you can install the &lt;code&gt;fluent-bit&lt;/code&gt; chart. The Helm chart comes with some good default settings for collecting container logs, but you can also customize it using a file called &lt;code&gt;values.yaml&lt;/code&gt; to set up things like where to get logs from, how to process them, and where to send them.&lt;/p&gt;
&lt;p&gt;If you prefer to have more control or you&amp;#39;re not using Helm, you can also deploy Fluent Bit using raw Kubernetes YAML files. This involves creating a &lt;code&gt;DaemonSet&lt;/code&gt; object that tells Kubernetes which Fluent Bit container image to use, how much resources it needs, which parts of the machine&amp;#39;s file system it needs access to (to get the container logs), and any other necessary settings. Along with the &lt;code&gt;DaemonSet&lt;/code&gt;, you&amp;#39;ll usually define a &lt;code&gt;ConfigMap&lt;/code&gt; to hold the Fluent Bit configuration file (&lt;code&gt;fluent-bit.conf&lt;/code&gt;), which tells Fluent Bit how to collect, process, and send the logs. You might also need to set up a ServiceAccount and some rules (RBAC roles and bindings) to give the Fluent Bit pods the permissions they need to talk to the Kubernetes API server (to get extra information about the containers) and to send logs to wherever you&amp;#39;ve configured.&lt;/p&gt;
&lt;p&gt;No matter how you choose to deploy it, the big advantage of using a &lt;code&gt;DaemonSet&lt;/code&gt; is that Kubernetes takes care of making sure Fluent Bit is running on each machine. If you add a new machine to your cluster, Kubernetes will automatically start a Fluent Bit pod on it. And if a machine fails, the Fluent Bit pod that was running there will be restarted on another available machine, ensuring you always have log collection across your entire cluster.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Step-by-step guide to setting up Fluent Bit to watch container logs.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To get Fluent Bit to collect logs from containers running in your Kubernetes cluster, you need to tell it where to look for the logs and how to understand them. This is usually done in Fluent Bit&amp;#39;s configuration file, which you often provide to the Fluent Bit &lt;code&gt;DaemonSet&lt;/code&gt; using a Kubernetes &lt;code&gt;ConfigMap&lt;/code&gt;. Here&amp;#39;s a simple guide:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tell Fluent Bit where to get logs:&lt;/strong&gt; In your &lt;code&gt;fluent-bit.conf&lt;/code&gt; file, you need to add an `` section. This tells Fluent Bit where to find the logs. For container logs in Kubernetes, the &lt;code&gt;tail&lt;/code&gt; plugin is commonly used. You&amp;#39;ll set Name &lt;code&gt;tail&lt;/code&gt; to use this plugin.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Point it to the log files:&lt;/strong&gt; The &lt;code&gt;Path&lt;/code&gt; setting inside the `` section tells Fluent Bit which files to watch. To get logs from all containers in a Kubernetes cluster, a common path is &lt;code&gt;/var/log/containers/\*.log&lt;/code&gt;. This usually catches the log files written by the software that runs your containers (like Docker or containerd).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Give the logs a tag:&lt;/strong&gt; The &lt;code&gt;Tag&lt;/code&gt; setting is important for identifying where the logs came from within Fluent Bit. You can set this to something like &lt;code&gt;kube.*&lt;/code&gt;. This tag will be used later to process and send the logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tell it how to read the logs:&lt;/strong&gt; The software that runs your containers writes logs in a specific way. You need to tell Fluent Bit how to understand these logs using the &lt;code&gt;Parser&lt;/code&gt; setting. If you&amp;#39;re using Docker, you&amp;#39;d use &lt;code&gt;docker&lt;/code&gt;. If you&amp;#39;re using other container software that follows the standard way of doing things in Kubernetes (called CRI), you might use &lt;code&gt;cri&lt;/code&gt;. Make sure you pick the parser that matches what your Kubernetes setup is using.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep track of where it&amp;#39;s been (optional but good):&lt;/strong&gt; The DB setting lets Fluent Bit remember where it stopped reading in the log files. This is important so it doesn&amp;#39;t re-read logs if it restarts or if the log files get rotated. You can specify a path to a database file, for example, &lt;code&gt;/var/log/flb_kube.db&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(Optional) Handle logs that span multiple lines:&lt;/strong&gt; Some applications write log messages that take up more than one line (like error messages with lots of details). You might need to set up a &lt;code&gt;multiline.parser&lt;/code&gt; option within the `` section to handle these correctly. Common options are &lt;code&gt;docker&lt;/code&gt; and &lt;code&gt;cri&lt;/code&gt;, which often include rules for this.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;#39;s an example of a basic `` section in your fluent-bit.conf:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;[INPUT]
    Name tail
    Path /var/log/containers/*.log
    Tag kube.*
    Parser docker
    DB /var/log/flb_kube.db
    Mem_Buf_Limit 5MB
    Skip_Long_Lines On
    Refresh_Interval 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells Fluent Bit to watch all files ending in &lt;code&gt;.log&lt;/code&gt; in the &lt;code&gt;/var/log/containers/&lt;/code&gt; folder, tag them with kube., understand them as Docker logs, and remember its place in the &lt;code&gt;/var/log/flb_kube.db&lt;/code&gt; file.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Using Fluent Bit filters to add Kubernetes info to your logs (like namespaces, pods, etc.).&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To make your container logs even more helpful, you can use Fluent Bit&amp;#39;s filter plugins to add extra information. The kubernetes filter is specifically designed to add details from Kubernetes itself to your logs, such as the namespace, pod name, container name, and any labels or annotations you&amp;#39;ve set on your containers. Here&amp;#39;s how to use this filter:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Add a filter section:&lt;/strong&gt; In your fluent-bit.conf, create a `` section. You can have multiple filter sections.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pick the Kubernetes filter:&lt;/strong&gt; Set the Name to kubernetes to use the Kubernetes filter plugin.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tell it which logs to filter:&lt;/strong&gt; Use the Match setting to specify which log records this filter should apply to. Usually, you&amp;#39;ll want to match the tag you set in the `` section (e.g., kube.*).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set up access to Kubernetes:&lt;/strong&gt; The kubernetes filter needs to talk to the Kubernetes API server to get the extra information. You&amp;#39;ll need to make sure these settings are correct, although in many Kubernetes setups, these are handled automatically:&lt;ul&gt;
&lt;li&gt;Kube_URL: The address of the Kubernetes API server (e.g., &lt;a href=&quot;https://kubernetes.default.svc&quot;&gt;https://kubernetes.default.svc&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Kube_CA_File: The path to the file that verifies the API server&amp;#39;s security certificate (e.g., /var/run/secrets/kubernetes.io/serviceaccount/ca.crt).&lt;/li&gt;
&lt;li&gt;Kube_Token_File: The path to the file containing the authentication token (e.g., /var/run/secrets/kubernetes.io/serviceaccount/token).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turn on metadata enrichment:&lt;/strong&gt; To include Kubernetes pod labels and annotations in the log information, set Labels and Annotations to On (or True).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Combine log content (optional):&lt;/strong&gt; If your container logs are in JSON format, you can use the Merge_Log option. If you turn this on, Fluent Bit will try to read the log field as JSON and add its contents to the main log record. You can also use Merge_Log_Key to put these merged fields under a specific name. The Keep_Log option lets you decide if you want to keep the original log field after merging.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;#39;s an example of a `` section using the kubernetes filter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;[FILTER]
    Name kubernetes
    Match kube.*
    Kube_URL https://kubernetes.default.svc
    Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
    Labels On
    Annotations On
    Merge_Log On
    Keep_Log Off
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup will add Kubernetes metadata, including labels and annotations, to all logs tagged with kube.*. It will also try to merge any JSON content found in the log field into the main record and remove the original log field.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Practical examples of setting up Fluent Bit for different Kubernetes logging needs.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Fluent Bit is really flexible and has lots of plugins, so you can set it up in many different ways to handle various Kubernetes logging scenarios. Here are a few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Basic Container Log Collection with Kubernetes Metadata:&lt;/strong&gt; This is the most common setup. You just combine the &lt;code&gt;tail&lt;/code&gt; input plugin (like we talked about earlier) with the kubernetes filter plugin (also shown before). This gets you logs from all your containers and adds important Kubernetes information to them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collecting Logs from Specific Namespaces or Pods:&lt;/strong&gt; While the kubernetes filter adds namespace and pod info, you can also target specific namespaces or pods right at the beginning. In the ``section using the&lt;code&gt;tail&lt;/code&gt; plugin, you can change the &lt;code&gt;Path&lt;/code&gt; setting to include specific patterns. For example, to only get logs from pods in the production namespace, you might use a path like &lt;code&gt;/var/log/containers/production/*.log&lt;/code&gt;. However, it&amp;#39;s usually more flexible to filter logs later in Loki or Grafana using the added metadata.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collecting System Logs from Nodes:&lt;/strong&gt; To get logs from the Kubernetes machines themselves (like kubelet logs or container runtime logs), you can use the systemd input plugin. In the `` section, set Name systemd and use the Systemd_Filter setting to specify which system services you want to collect logs from, such as _SYSTEMD_UNIT=kubelet.service or _SYSTEMD_UNIT=containerd.service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collecting Kubernetes Events:&lt;/strong&gt; Kubernetes events give you valuable insights into what&amp;#39;s happening in your cluster. Fluent Bit can collect these using the kubernetes_events input plugin. In the ``section, set Name kubernetes_events and configure the Kube_URL, Kube_CA_File, and Kube_Token_File settings as needed. Keep in mind that it&amp;#39;s often better to run this as a separate Deployment with only one copy, rather than as part of the Fluent Bit&lt;code&gt;DaemonSet&lt;/code&gt;, to avoid getting duplicate events.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These examples show how flexible Fluent Bit is for different Kubernetes logging needs. By choosing the right input plugins and setting up the filter and output stages correctly, you can customize your log collection process to fit your specific monitoring and analysis requirements.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Setting Up Loki: Your Scalable Log Storage Backend&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;How to install and configure Loki on Kubernetes using Helm.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The easiest and best way to install Loki on your Kubernetes cluster is by using the official Grafana Helm chart. Helm makes it much simpler to deploy and manage applications in Kubernetes, which is great for setting up complex systems like Loki. Here&amp;#39;s a step-by-step guide:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Add the Grafana Helm Repository:&lt;/strong&gt; First, you need to tell Helm where to find the Grafana charts, which include Loki. Open your terminal and run: helm repo add grafana &lt;a href=&quot;https://grafana.github.io/helm-charts&quot;&gt;https://grafana.github.io/helm-charts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Update Helm Repositories:&lt;/strong&gt; After adding the repository, it&amp;#39;s a good idea to update your local list of charts to make sure you have the latest version of the Loki chart. Run: helm repo update.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Customize Loki Configuration (Optional but Recommended):&lt;/strong&gt; Before you install Loki, you&amp;#39;ll probably want to change some of its settings to match your needs. You do this by editing the &lt;code&gt;values.yaml&lt;/code&gt; file that comes with the Loki Helm chart. You can either see the default settings by running helm show values grafana/loki &amp;gt; loki.yaml and then editing the loki.yaml file, or you can create your own &lt;code&gt;values.yaml&lt;/code&gt; file with just the settings you want to change. This file lets you configure things like where Loki stores its data (like on your local machine or in cloud storage like S3), how it&amp;#39;s deployed (all in one place or as separate components), how much resources it can use, and more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Install Loki using Helm:&lt;/strong&gt; Once you&amp;#39;ve (optionally) customized your &lt;code&gt;values.yaml&lt;/code&gt; file, you can install Loki into your Kubernetes cluster. It&amp;#39;s a good idea to create a separate space for Loki to keep its resources organized. You can do this with kubectl create namespace loki if you haven&amp;#39;t already. Then, use the helm install command to deploy Loki. If you&amp;#39;re using a custom &lt;code&gt;values.yaml&lt;/code&gt; file, the command will look something like this: helm install loki grafana/loki -n loki --create-namespace -f loki.yaml. The --create-namespace part will create the loki namespace if it doesn&amp;#39;t exist yet.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After you run this command, Helm will deploy Loki and all its related parts into your Kubernetes cluster. You can check if it worked by looking at the status of the pods in the loki namespace using kubectl get pods -n loki.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Understanding Loki&amp;#39;s deployment modes: Monolithic, Simple Scalable, and Microservices.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Loki gives you different ways to set it up, depending on how much you expect to use it and how complex you want things to be. Knowing about these modes helps you pick the right one for your situation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Monolithic Mode:&lt;/strong&gt; This is the simplest way to run Loki. All of Loki&amp;#39;s main parts – the ingester, distributor, querier, and others – run together as one single program. This mode is easy to set up and is great for getting started, for testing things out, and for production environments that don&amp;#39;t have a huge amount of logs, usually up to around 20GB per day. You can run multiple copies of it to handle more load, but all the parts scale together.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simple Scalable Deployment (SSD):&lt;/strong&gt; This mode is a middle ground between the simplicity of monolithic mode and the scalability of microservices mode. SSD separates Loki&amp;#39;s functions into three main areas:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Write Target:&lt;/strong&gt; This includes the distributor and ingester, which are responsible for receiving and saving logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read Target:&lt;/strong&gt; This includes the query frontend and querier, which handle log searches.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backend Target:&lt;/strong&gt; This includes the compactor, index gateway, ruler, and other background processes. This separation lets you scale the read and write parts independently, which are often the busiest parts of Loki. SSD is a good choice for handling a moderate to large amount of logs, up to a few terabytes per day, and it&amp;#39;s often the default mode when you use the Loki Helm chart.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microservices Mode:&lt;/strong&gt; If you have a very large Loki setup that needs to handle terabytes of logs every day, or if you want very fine control over how each part of Loki scales and uses resources, then microservices mode is the way to go. In this mode, each of Loki&amp;#39;s components (distributor, ingester, query frontend, querier, compactor, index gateway, ruler, etc.) runs as a separate program. This gives you the most flexibility and scalability but also makes things more complex to manage. Microservices mode is generally recommended for advanced users with specific needs for performance and scaling, especially in Kubernetes environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Choosing the right deployment mode depends on how many logs you expect, how much you need to scale, and how much complexity you&amp;#39;re comfortable with. A common approach is to start with monolithic or simple scalable mode and then move to microservices mode as your needs grow.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Choosing the right storage options for Loki: from local storage to cloud-based object stores like S3.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Loki needs a place to store the log data it collects. It mainly stores two types of things: &lt;strong&gt;chunks&lt;/strong&gt;, which are the actual compressed log entries, and the &lt;strong&gt;index&lt;/strong&gt;, which is like a table of contents that helps Loki find the logs quickly. The storage you choose affects how well Loki performs, how much it can scale, how much it costs, and how reliable it is. Here&amp;#39;s a look at the common storage options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Filesystem (Local Storage):&lt;/strong&gt; You can set up Loki to store both chunks and the index on the local hard drive of the machine it&amp;#39;s running on. While this is the easiest to set up and is often used for testing or development, it&amp;#39;s &lt;strong&gt;generally not recommended for production&lt;/strong&gt;. Local storage doesn&amp;#39;t scale well and isn&amp;#39;t as reliable as you&amp;#39;d want for important data. If the machine running Loki fails, you might lose your logs. Also, it&amp;#39;s harder to reliably scale Loki across multiple machines with local storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Object Storage (S3, GCS, Azure Blob Storage, etc.):&lt;/strong&gt; For production environments, using a scalable and reliable object storage service is the &lt;strong&gt;most recommended option&lt;/strong&gt; for Loki. Loki works with several popular object storage providers, including:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Amazon S3 (Simple Storage Service):&lt;/strong&gt; A highly available and durable storage service from AWS. It&amp;#39;s a popular choice for Loki users on AWS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Cloud Storage (GCS):&lt;/strong&gt; Google Cloud&amp;#39;s version of object storage, offering similar benefits to S3 and good integration with other Google Cloud services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Blob Storage:&lt;/strong&gt; Microsoft Azure&amp;#39;s scalable object storage solution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IBM Cloud Object Storage (COS):&lt;/strong&gt; An object storage service on IBM Cloud.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Baidu Object Storage (BOS):&lt;/strong&gt; Baidu Cloud&amp;#39;s object storage offering.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alibaba Object Storage Service (OSS):&lt;/strong&gt; Alibaba Cloud&amp;#39;s object storage service. Using object storage gives you practically unlimited storage, high availability, and cost-effectiveness for keeping your logs long-term. You&amp;#39;ll need to configure Loki with the right access information and details about your storage bucket.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other Options:&lt;/strong&gt; Loki also supports other storage systems, though some are no longer recommended. For example, you can use Apache Cassandra to store chunks. Additionally, Loki can be set up to use S3 API-compatible storage like MinIO, which you can host yourself, giving you an on-premises object storage solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For any production setup of Loki, &lt;strong&gt;it&amp;#39;s highly recommended to choose a scalable and durable object storage service like S3, GCS, or Azure Blob Storage&lt;/strong&gt; to make sure your centralized logging system is reliable and cost-efficient. Local storage should mainly be used for testing and development.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;A look at a basic Loki configuration file and essential parameters.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Loki&amp;#39;s behavior is mostly controlled by a YAML configuration file, usually named loki.yaml. This file lets you set up various aspects of the Loki server and its components. Here are some of the important settings you&amp;#39;ll find in a basic Loki configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;auth_enabled:&lt;/strong&gt; This top-level setting is either true or false and turns on or off authentication for Loki&amp;#39;s API. For simpler setups, especially on internal networks, this is often set to false. In production, you&amp;#39;ll likely want to enable authentication for security.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;server:&lt;/strong&gt; This section configures the HTTP and gRPC servers that Loki uses to listen for incoming requests. Key settings include:&lt;ul&gt;
&lt;li&gt;http_listen_port: The port Loki listens on for HTTP requests (default is 3100).&lt;/li&gt;
&lt;li&gt;grpc_listen_port: The port for gRPC requests (default is 9096).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;common:&lt;/strong&gt; This section contains settings that are used by different parts of Loki. Important settings include:&lt;ul&gt;
&lt;li&gt;path_prefix: The main directory Loki uses for local storage (if you&amp;#39;re using it).&lt;/li&gt;
&lt;li&gt;ring: Configures how Loki coordinates its ingesters in distributed setups.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;storage_config:&lt;/strong&gt; This is a very important section that specifies where Loki stores its chunks and index. It usually has subsections for different storage options, such as:&lt;ul&gt;
&lt;li&gt;filesystem: Configures local storage, with settings like chunks_directory and rules_directory.&lt;/li&gt;
&lt;li&gt;aws: Configures Amazon S3 storage, with settings like bucket_name, region, access_key_id, and secret_access_key (or using IAM roles). Similar subsections exist for other object storage providers like gcs and azure.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;schema_config:&lt;/strong&gt; This section defines how Loki organizes and indexes its data over time. It has a list called configs, where each entry specifies a time range (from) and the storage configuration to use during that time (store, object_store, schema, index). The store type can be tsdb (Time Series Database, recommended for newer Loki versions) or boltdb-shipper (recommended for older versions).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ingester:&lt;/strong&gt; This section configures the ingester component, which receives and writes logs. Important settings include:&lt;ul&gt;
&lt;li&gt;lifecycler: Settings for managing ingester instances in distributed modes.&lt;/li&gt;
&lt;li&gt;chunk_idle_period: How long an inactive chunk in memory will wait before being saved to storage.&lt;/li&gt;
&lt;li&gt;max_chunk_age: The maximum time a chunk can stay in memory before being saved to storage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is just a basic overview, and Loki&amp;#39;s configuration file has many more options for fine-tuning its behavior. Understanding these essential settings will give you a good start for deploying and managing your Loki instance effectively. You can find more detailed configuration examples in the official Loki documentation.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Grafana: Your Window into the Logs&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;How to seamlessly add Loki as a data source in your Grafana instance.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Connecting Loki to Grafana is a simple process that lets you see and analyze your log data within Grafana&amp;#39;s easy-to-use interface. Here&amp;#39;s how you do it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Go to Data Sources:&lt;/strong&gt; Open Grafana in your web browser. On the left sidebar, hover over the &lt;strong&gt;Connections&lt;/strong&gt; icon (it looks like a plug) and then click on &lt;strong&gt;Data sources&lt;/strong&gt;. If you&amp;#39;re using an older version of Grafana, you might find &lt;strong&gt;Data Sources&lt;/strong&gt; under the &lt;strong&gt;Configuration&lt;/strong&gt; menu (the gear icon).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add New Data Source:&lt;/strong&gt; On the Data Sources page, you&amp;#39;ll see a button that says &lt;strong&gt;Add new data source&lt;/strong&gt;. Click it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pick Loki:&lt;/strong&gt; You&amp;#39;ll see a list of different data source plugins. In the search bar at the top, type &amp;quot;Loki&amp;quot; to find it quickly. Click on the &lt;strong&gt;Loki&lt;/strong&gt; option to select it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enter Loki Connection Details:&lt;/strong&gt; Now you&amp;#39;ll see the settings page for the Loki data source. The most important field here is the &lt;strong&gt;URL&lt;/strong&gt;. In this box, you need to type in the network address of your Loki server. If Loki is running in the same Kubernetes cluster, you&amp;#39;ll usually use its internal name and port, like &lt;a href=&quot;http://loki:3100&quot;&gt;http://loki:3100&lt;/a&gt;. If Loki is on a different machine or network, you&amp;#39;ll need to use its IP address or hostname and the port it&amp;#39;s listening on (which is usually 3100).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handle Multi-Tenancy (If Needed):&lt;/strong&gt; If your Loki setup is using multi-tenancy (which it does by default), you&amp;#39;ll need to provide your tenant ID. You do this by adding a custom HTTP header in the Grafana data source settings. Under the &lt;strong&gt;HTTP settings&lt;/strong&gt; section, click the &lt;strong&gt;+ Add header&lt;/strong&gt; button. In the &lt;strong&gt;Header&lt;/strong&gt; field, type X-Scope-OrgID, and in the &lt;strong&gt;Value&lt;/strong&gt; field, enter your specific tenant ID. If you&amp;#39;ve turned off multi-tenancy in your Loki configuration, you can skip this step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save and Test:&lt;/strong&gt; Once you&amp;#39;ve entered the URL and (if needed) the tenant ID, scroll to the bottom of the page and click the &lt;strong&gt;Save &amp;amp; test&lt;/strong&gt; button. Grafana will try to connect to your Loki server and will show a success message if it works. If there are any problems, it will show an error message to help you figure out what&amp;#39;s wrong.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;#39;s it! You&amp;#39;ve now connected Loki as a data source to your Grafana, and you can start looking at and visualizing your log data.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Exploring and querying your logs using Grafana&amp;#39;s intuitive interface.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Once you&amp;#39;ve successfully connected Loki to Grafana, you can start exploring and searching through your logs using Grafana&amp;#39;s easy-to-use &lt;strong&gt;Explore&lt;/strong&gt; view. This is a really handy tool for looking into your logs without having to create a full dashboard. Here&amp;#39;s how to use it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Open Explore View:&lt;/strong&gt; In the Grafana interface, look for the &lt;strong&gt;Explore&lt;/strong&gt; icon on the left sidebar. It usually looks like a compass. Click on it to open the Explore view.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Select Loki Data Source:&lt;/strong&gt; At the top left of the Explore view, you&amp;#39;ll see a dropdown menu where you can choose your data source. Click on it and select the Loki data source you just added.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build Your LogQL Query:&lt;/strong&gt; You can start building your search using the &lt;strong&gt;Label filters&lt;/strong&gt;. If you click on the &lt;strong&gt;Label filters&lt;/strong&gt; button, you&amp;#39;ll see a list of labels from your Loki data. Pick a label from the dropdown, then choose an operator (like =, !=, =&lt;del&gt;, !&lt;/del&gt;) and type in a value to filter your log streams based on these labels. For example, you might select the app label, the = operator, and enter the name of your application to see only the logs from that application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type in LogQL Directly:&lt;/strong&gt; If you know LogQL or want to do more complex searches, you can type your queries directly into the query editor panel below the data source selection. Grafana will even give you suggestions for labels and LogQL functions as you type. You can also click the &lt;strong&gt;Kick start your query&lt;/strong&gt; button to see some common query examples that you can adapt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run Your Search:&lt;/strong&gt; Once you&amp;#39;ve built your query, either by using the label filters or by typing it in, click the &lt;strong&gt;Run query&lt;/strong&gt; button (it often looks like a play icon). Grafana will send your LogQL query to Loki and show you the results.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;See the Results:&lt;/strong&gt; The log query results are usually shown in two main ways:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Log Lines:&lt;/strong&gt; Below the query editor, you&amp;#39;ll see a list of individual log entries that match your search. Each entry will show the time the log was recorded and the actual log message.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logs Volume Graph:&lt;/strong&gt; Above the log lines, Grafana often shows a graph that displays how many logs matched your query over the time period you selected. This can help you see trends and identify times with lots of activity or few logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Grafana&amp;#39;s Explore view gives you an easy and interactive way to look into your log data stored in Loki, letting you filter by metadata, search for specific content, extract structured data, and even get valuable metrics from your log data. If you&amp;#39;re already familiar with PromQL, you&amp;#39;ll find LogQL easier to learn and use.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Building insightful dashboards to visualize log data and identify trends.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While Grafana&amp;#39;s Explore view is great for quick log checks, &lt;strong&gt;Dashboards&lt;/strong&gt; let you create permanent and shareable views of your log data. This helps you monitor things over time and spot trends. Here&amp;#39;s how to build useful log dashboards with Grafana and Loki:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create a New Dashboard:&lt;/strong&gt; In Grafana, click the &lt;strong&gt;+ Create&lt;/strong&gt; button on the left sidebar and select &lt;strong&gt;Dashboard&lt;/strong&gt;. You&amp;#39;ll get a new, empty dashboard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add a Logs Panel:&lt;/strong&gt; Click on &amp;quot;Add new panel&amp;quot; (or the &amp;quot;+&amp;quot; icon at the top) and choose &amp;quot;Add an empty panel.&amp;quot; In the panel editor that pops up, under &amp;quot;Visualization,&amp;quot; select &lt;strong&gt;Logs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set Up the Logs Panel:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data Source:&lt;/strong&gt; In the &amp;quot;Query&amp;quot; tab of the panel editor, pick your Loki data source from the dropdown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LogQL Query:&lt;/strong&gt; In the query editor, type in your LogQL query to get the specific logs you want to see. You can use label filters to narrow down the log streams and filter operators to search for specific words or phrases in the logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Panel Options:&lt;/strong&gt; In the &amp;quot;Panel&amp;quot; tab, you can change how the logs are displayed, like whether to show timestamps, unique labels, and whether to wrap long lines. You can also give your panel a title.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visualize Trends with Metric Queries:&lt;/strong&gt; To see trends and patterns, you can use LogQL to turn your logs into metrics. For example, you can use the &lt;code&gt;count_over_time&lt;/code&gt; function to count how many error logs you had in the last hour. To do this, add a new panel to your dashboard (or edit an existing one). In the &amp;quot;Visualization&amp;quot; section, select a time-series visualization like &lt;strong&gt;Time series&lt;/strong&gt; or &lt;strong&gt;Bar chart&lt;/strong&gt;. In the &amp;quot;Query&amp;quot; tab, select your Loki data source and write a LogQL metric query. For example, to count error logs from your application, your query might look like: &lt;code&gt;count_over_time({app=&amp;quot;my-app&amp;quot;, level=&amp;quot;error&amp;quot;}[1h])&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Pre-built Dashboards:&lt;/strong&gt; The Grafana community has created lots of helpful dashboards for visualizing Loki logs. You can find and import these from the Grafana Labs website (&lt;a href=&quot;https://grafana.com/grafana/dashboards/&quot;&gt;https://grafana.com/grafana/dashboards/&lt;/a&gt;). Just search for &amp;quot;Loki&amp;quot; to find dashboards you can use as they are or customize.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Customize and Organize:&lt;/strong&gt; Keep adding panels to your dashboard to visualize different parts of your log data. You can move panels around and resize them. Use clear and descriptive titles for your panels to make your dashboard easy to understand.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By building these insightful dashboards, you can create a central place to monitor your log data, allowing your team to quickly see how your systems are doing and spot potential problems early.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Introduction to LogQL: crafting powerful queries to filter and analyze your logs.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;LogQL (Loki Query Language) is the powerful language you use to talk to the logs stored in Grafana Loki. Inspired by Prometheus&amp;#39;s PromQL, LogQL lets you filter and analyze your logs in a flexible and efficient way. A LogQL query usually has two main parts: the &lt;strong&gt;log stream selector&lt;/strong&gt; and the &lt;strong&gt;log pipeline&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;log stream selector&lt;/strong&gt; is the first part of a LogQL query and it&amp;#39;s used to pick out the specific log streams you&amp;#39;re interested in based on their labels. Labels are like tags – key-value pairs that give you extra information about the log stream, like the application name, environment, or Kubernetes pod. Log stream selectors are written inside curly braces {} and use label matchers to filter streams. Common label matchers include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;=: Equal to (e.g., &lt;code&gt;{app=&amp;quot;my-app&amp;quot;}&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;!=: Not equal to (e.g., &lt;code&gt;{environment!=&amp;quot;production&amp;quot;}&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;=~: Matches the regular expression (e.g., &lt;code&gt;{level=~&amp;quot;error|warn&amp;quot;}&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;!~: Does not match the regular expression (e.g., &lt;code&gt;{http_method!~&amp;quot;GET|OPTIONS&amp;quot;}&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use commas to combine multiple label matchers to make your selection even more specific. For example, &lt;code&gt;{app=&amp;quot;my-app&amp;quot;, environment=&amp;quot;staging&amp;quot;}&lt;/code&gt; will only select log streams that have both the app label with the value &amp;quot;my-app&amp;quot; and the environment label with the value &amp;quot;staging&amp;quot;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;log pipeline&lt;/strong&gt; is the second part of a LogQL query and it&amp;#39;s used to further process and filter the log lines you&amp;#39;ve selected. The pipeline is made up of one or more &lt;strong&gt;pipeline operators&lt;/strong&gt;, which are separated by the pipe symbol |. Some common pipeline operators include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Filter Operators:&lt;/strong&gt; These operators let you filter log lines based on what&amp;#39;s inside them:&lt;ul&gt;
&lt;li&gt;|=: Log line contains the specified string (e.g., &lt;code&gt;{app=&amp;quot;my-app&amp;quot;} |= &amp;quot;error&amp;quot;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;!=: Log line does not contain the specified string (e.g., &lt;code&gt;{app=&amp;quot;my-app&amp;quot;}!= &amp;quot;debug&amp;quot;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;|~: Log line matches the specified regular expression (e.g., &lt;code&gt;{app=&amp;quot;my-app&amp;quot;} |~ &amp;quot;exception.\* occurred&amp;quot;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;!~: Log line does not match the specified regular expression (e.g., &lt;code&gt;{app=&amp;quot;my-app&amp;quot;}!~ &amp;quot;healthcheck&amp;quot;&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parser Expressions:&lt;/strong&gt; These operators let you pull out structured data from your log lines and turn them into new labels:&lt;ul&gt;
&lt;li&gt;json: Parses log lines as JSON and creates new labels from the JSON keys.&lt;/li&gt;
&lt;li&gt;logfmt: Parses log lines in the logfmt format (key=value pairs).&lt;/li&gt;
&lt;li&gt;regexp: Lets you define your own regular expressions to extract data into named capture groups, which then become new labels.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metric Queries:&lt;/strong&gt; LogQL lets you generate metrics from your log data using functions like:&lt;ul&gt;
&lt;li&gt;count_over_time: Counts the number of log entries within a specified time range (e.g., &lt;code&gt;count_over_time({app=&amp;quot;my-app&amp;quot;}[5m])&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;rate: Calculates how many log entries happened per second (e.g., &lt;code&gt;rate({app=&amp;quot;my-app&amp;quot;}[1m])&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Aggregation functions like sum, avg, min, and max can be used to combine these metrics across different log streams based on labels (e.g., &lt;code&gt;sum(rate({app=~&amp;quot;.\*&amp;quot;}[1m])) by (app)&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LogQL gives you a powerful and flexible way to search and analyze your logs in Loki, letting you filter by metadata, search for specific content, extract structured data, and even get valuable metrics from your log data. If you&amp;#39;re already familiar with PromQL, you&amp;#39;ll find LogQL easier to learn and use.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions (FAQ)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;When should you choose Loki over the traditional ELK stack?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Deciding between Loki and the traditional ELK (Elasticsearch, Logstash, Kibana) stack often comes down to what&amp;#39;s most important to you. Loki really shines when you want a &lt;strong&gt;lightweight and affordable logging solution&lt;/strong&gt;, especially if you&amp;#39;re working with dynamic, cloud-based environments like Kubernetes. Its efficient way of indexing logs using labels means it uses much less resources and storage compared to ELK, which indexes every word.&lt;/p&gt;
&lt;p&gt;If your organization is already using &lt;strong&gt;Grafana and Prometheus&lt;/strong&gt; to monitor metrics, Loki fits right into this setup, giving you a single place to see all your monitoring data. This can make your overall monitoring strategy simpler and mean you don&amp;#39;t have to manage as many different systems.&lt;/p&gt;
&lt;p&gt;Loki is also a great choice if you mostly need to &lt;strong&gt;filter logs by metadata&lt;/strong&gt; (like application name, environment, or Kubernetes pod) to understand where your logs are coming from. While Loki can do content-based searching, it&amp;#39;s really good at filtering by these labels.&lt;/p&gt;
&lt;p&gt;On the other hand, the ELK stack is still a strong option if you need &lt;strong&gt;advanced search features&lt;/strong&gt; and the ability to do complex searches across all the text in your logs. If you need to really dig into unstructured log data and search for any keyword, ELK&amp;#39;s powerful search might be a better fit.&lt;/p&gt;
&lt;p&gt;Also, if you&amp;#39;re looking for something that&amp;#39;s &lt;strong&gt;easier to set up and maintain&lt;/strong&gt;, especially in containerized environments, Loki&amp;#39;s design is generally considered less complex than the ELK stack, which has multiple components.&lt;/p&gt;
&lt;p&gt;Basically, the choice often boils down to whether you prioritize cost and simplicity (Loki) or advanced search capabilities (ELK). Your specific needs, the systems you already have, and the resources available will help you decide.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some common challenges faced when implementing this centralized logging solution?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Setting up a centralized logging system with Loki, Grafana, and Fluent Bit has lots of benefits, but it can also come with some challenges. One common issue is &lt;strong&gt;dealing with the sheer amount of log data&lt;/strong&gt; that modern, spread-out systems produce, especially in busy Kubernetes and microservices environments. This can lead to high costs for storing and processing all that data.&lt;/p&gt;
&lt;p&gt;Another challenge is &lt;strong&gt;making sure the log data is good quality and consistent&lt;/strong&gt; across different services and applications that might be written in different languages and use different logging tools. If logs aren&amp;#39;t in a consistent format, it can be harder to understand and analyze them, which makes your centralized logging system less effective.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Getting Fluent Bit set up correctly&lt;/strong&gt; to collect logs from all the right places in a Kubernetes cluster, including application containers, system components, and maybe even Kubernetes events, can sometimes be tricky. You need to pay close attention to the configuration details to make sure you&amp;#39;re not missing important logs or collecting too much unnecessary information.&lt;/p&gt;
&lt;p&gt;Sometimes you might run into &lt;strong&gt;problems with the different parts not being able to talk to each other&lt;/strong&gt; – Fluent Bit, Loki, and Grafana – especially in complex network setups or if you have firewalls and network rules in place. Making sure each component can communicate with the others is key to a working logging pipeline.&lt;/p&gt;
&lt;p&gt;If your team is new to Loki, &lt;strong&gt;learning how to use LogQL effectively&lt;/strong&gt; to search and analyze logs can take some time. While it&amp;#39;s similar to PromQL, LogQL has its own rules and quirks that you&amp;#39;ll need to get used to.&lt;/p&gt;
&lt;p&gt;Finally, like any system that&amp;#39;s spread out, you need to think about &lt;strong&gt;what happens if something fails in your logging pipeline&lt;/strong&gt; and how to make sure your log data stays safe and reliable as it&amp;#39;s being collected, moved, and stored. Setting up good buffering and retry mechanisms is important to prevent losing data.&lt;/p&gt;
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can you effectively manage log volume and control costs?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Keeping track of how many logs you&amp;#39;re generating and managing the costs associated with them is really important for having a sustainable centralized logging system. Here are some effective ways to do this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Only keep what you need:&lt;/strong&gt; Think about what logs are really important for troubleshooting, security, and meeting any rules you have to follow. Don&amp;#39;t just collect everything; focus on the data that gives you valuable insights.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filter out the noise:&lt;/strong&gt; Configure Fluent Bit to filter out logs that aren&amp;#39;t really necessary or are just too much detail, especially in production environments. You can set up rules to only keep logs of a certain severity level (like errors and warnings).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use smart storage:&lt;/strong&gt; If you&amp;#39;re using cloud storage for Loki, consider using different storage tiers. Keep recent, frequently accessed logs on faster, more expensive storage and move older, less accessed logs to cheaper storage options.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set retention policies:&lt;/strong&gt; Decide how long you need to keep your logs based on your requirements and costs. Regularly review these policies and set up automated processes to delete or archive older logs to save space.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Be smart with labels:&lt;/strong&gt; In Loki, how you label your logs affects how efficiently it can store and search them. Avoid using labels that have lots of different values (high cardinality), as this can impact performance and costs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turn logs into metrics:&lt;/strong&gt; For logs that are mostly about counting events or tracking rates, consider converting them into metrics within Fluent Bit or Loki. Metrics are generally more efficient for tracking trends over time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep an eye on your costs:&lt;/strong&gt; If you&amp;#39;re using a managed service like Grafana Cloud for Loki, use their cost management tools to see where your log volume is coming from and find ways to optimize your spending.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By using a combination of these strategies, you can effectively manage the amount of log data you&amp;#39;re dealing with in your centralized logging system and keep your costs under control.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h3&gt;&lt;strong&gt;Tips and tricks for troubleshooting common issues with Loki, Grafana, and Fluent Bit.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;When something goes wrong with your logging setup involving Fluent Bit, Loki, and Grafana, it&amp;#39;s important to have a systematic way to figure out what&amp;#39;s happening. Here are some tips and tricks to help you troubleshoot common issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Check the logs of each part:&lt;/strong&gt; The first thing you should do is look at the logs from Fluent Bit, Loki, and Grafana. Use kubectl logs (if you&amp;#39;re in Kubernetes) or the appropriate commands for your environment to see if there are any error messages or anything unusual happening.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Double-check your configuration:&lt;/strong&gt; Make sure your configuration files (fluent-bit.conf, loki.yaml, and Grafana&amp;#39;s data source settings) don&amp;#39;t have any typos or incorrect settings. Pay close attention to server addresses, ports, API endpoints, and storage configurations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Is Fluent Bit talking to Loki?&lt;/strong&gt; Make sure Fluent Bit is set up correctly to send logs to the right Loki address. Check the host, port, and uri settings in your Fluent Bit Loki output plugin. If you&amp;#39;re using any kind of authentication (like a tenant ID or API key), make sure that&amp;#39;s also configured correctly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Is Grafana talking to Loki?&lt;/strong&gt; In Grafana, go to your Loki data source settings and click the &amp;quot;Save &amp;amp; test&amp;quot; button to see if Grafana can connect to your Loki server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test your LogQL queries:&lt;/strong&gt; Use Grafana&amp;#39;s Explore view to try out your LogQL queries. If you&amp;#39;re not seeing the logs you expect, try simplifying your query or using the label browser to see what labels are available in your Loki instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check your network:&lt;/strong&gt; If you&amp;#39;re in Kubernetes, make sure there aren&amp;#39;t any network rules or firewalls blocking communication between Fluent Bit, Loki, and Grafana. Verify that the necessary services are running and accessible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Permissions matter:&lt;/strong&gt; Make sure Fluent Bit has permission to read logs from the file system (especially in Kubernetes, where you need to set up volume mounts correctly) and that Loki has permission to write to its storage (like your S3 bucket).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Watch out for timestamp issues:&lt;/strong&gt; If the timestamps in your application logs don&amp;#39;t match what you&amp;#39;re seeing in Grafana, check the timestamp parsing settings in your Fluent Bit input plugin. You might need to adjust the Time_Key and Time_Format settings to match your log format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;See if Fluent Bit is even outputting logs:&lt;/strong&gt; If logs aren&amp;#39;t showing up in Loki, try temporarily setting up Fluent Bit to output logs to the standard output (stdout output plugin) to see if Fluent Bit is actually collecting and processing the logs correctly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Look for Loki ingester issues:&lt;/strong&gt; If you see errors in Loki&amp;#39;s logs related to ingesting data, check the configuration of your ingesters, especially the storage settings and any limits you might have set.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By systematically checking these things, you should be able to figure out and fix most common issues you might encounter when setting up and running your centralized logging system with Loki, Grafana, and Fluent Bit.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion: Embrace Centralized Logging for a Healthier System&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In today&amp;#39;s complex and spread-out IT environments, having a central place for all your logs isn&amp;#39;t just a nice-to-have; it&amp;#39;s essential for really understanding what&amp;#39;s going on with your systems. By bringing together log data from all different sources into one easy-to-access platform, organizations can get a ton of benefits, from fixing problems faster and improving security to meeting compliance rules and gaining deeper insights into how their systems are behaving.&lt;/p&gt;
&lt;p&gt;The powerful combination of Loki, Grafana, and Fluent Bit offers a great way to build a modern, scalable, and cost-effective centralized logging system, especially if you&amp;#39;re using Kubernetes and microservices. Fluent Bit works hard to collect and enrich logs from your infrastructure. Loki provides a scalable and affordable place to store these logs, indexing them in a way that makes searching fast. And Grafana gives you an intuitive and feature-rich interface to explore, visualize, and get alerts from your log data, turning raw information into useful insights.&lt;/p&gt;
&lt;p&gt;While setting up such a system might have some initial challenges, the long-term benefits of having better visibility, resolving incidents quicker, and improving your system&amp;#39;s health are well worth the effort. By adopting centralized logging with these powerful open-source tools, you can take a big step towards having a more observable, resilient, and ultimately healthier IT setup.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/loki/latest/get-started/overview/&quot;&gt;Grafana Loki Official Documentation - Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/grafana/latest/introduction/&quot;&gt;Grafana Official Documentation - About Grafana&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fluentbit.io/&quot;&gt;Fluent Bit Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.fluentbit.io/manual/installation/kubernetes&quot;&gt;Fluent Bit Documentation - Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/loki/latest/get-started/deployment-modes/&quot;&gt;Grafana Loki Documentation - Deployment Modes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/loki/latest/operations/storage/&quot;&gt;Grafana Loki Documentation - Storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/loki/latest/query/&quot;&gt;Grafana Loki Documentation - LogQL: Log query language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/grafana/latest/datasources/loki/&quot;&gt;Grafana Documentation - Configure Loki data source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/cluster-administration/logging/&quot;&gt;Kubernetes Documentation - Logging Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://signoz.io/blog/centralized-logging/&quot;&gt;Centralized Logging with Open Source Tools - OpenTelemetry and SigNoz&lt;/a&gt; (Provides good context on centralized logging)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.fluentbit.io/manual/pipeline/outputs/loki&quot;&gt;Fluent Bit Documentation - Loki Output Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/grafana/loki&quot;&gt;Grafana Loki GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fluent/fluent-bit&quot;&gt;Fluent Bit GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kubeblogs.com/loki-vs-elasticsearch/&quot;&gt;Loki vs. Elasticsearch: Choosing the Right Logging System for You - KubeBlogs&lt;/a&gt; (Good comparison article)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chronosphere.io/learn/fluent-bit-loki/&quot;&gt;How to send Logs to Loki using Fluent Bit - Chronosphere&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Observability</category><category>Logging</category><category>Kubernetes</category><category>Monitoring</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0081-centralized-logging-loki-grafana-fluent-bit/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Karpenter vs. Cluster Autoscaler on AWS: Picking the Right Tool for Your Kubernetes Scaling</title><link>https://mkabumattar.com/blog/post/karpenter-vs-cluster-autoscaler-aws-kubernetes-scaling/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/karpenter-vs-cluster-autoscaler-aws-kubernetes-scaling/</guid><description>Compare Karpenter and Cluster Autoscaler on AWS for Kubernetes scaling. Understand their architecture, performance, cost efficiency, and choose the right tool for your needs.</description><pubDate>Sat, 31 May 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You know how it is with modern apps – they can be super busy one minute and then quiet the next. If you&amp;#39;re using Kubernetes on Amazon Web Services (AWS), making sure your setup can handle these ups and downs automatically is a big deal. It keeps your apps running smoothly, uses your resources wisely, and saves you money. Trying to change the number of computers (nodes) in your Kubernetes setup by hand is a real headache. You might end up paying for computers you don&amp;#39;t need or your apps might slow down when things get busy. That&amp;#39;s where tools like Karpenter and Cluster Autoscaler come in. They automatically take care of adding and removing computers in your Kubernetes world on AWS. This article will give you a good look at both of these tools, what they do, what&amp;#39;s good about them, and what you should think about when choosing between them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First Things First:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&amp;#39;s Karpenter, and How Does It Work with AWS?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Karpenter is like a smart helper for your Kubernetes setup on AWS. It&amp;#39;s an open-source tool made by AWS that&amp;#39;s really good at managing your computer power. Unlike older ways of doing this, Karpenter figures out exactly what computer resources you need, right when you need them, based on what your apps are actually doing. To make this happen, Karpenter talks directly to AWS&amp;#39;s Elastic Compute Cloud (EC2) in a special way, so it can get new computers up and running really fast.&lt;/p&gt;
&lt;p&gt;The way Karpenter works is based on two main things in your Kubernetes setup: NodePool (which used to be called Provisioner) and EC2NodeClass (which was AWSNodeTemplate). The EC2NodeClass is where you tell AWS-specific things about your computers, like what kind of operating system image to use, which networks to connect to, and what security settings to have. The NodePool is where you set broader rules and preferences for getting new computers, like what types of computers you&amp;#39;d prefer, which locations they should be in, and even how long they should stick around. One of the cool things about Karpenter is that it can work with lots of different kinds of computers on AWS, in different places, and even using cheaper options like Spot Instances, without you having to set up a bunch of different groups of computers beforehand. Karpenter keeps an eye on the apps in your Kubernetes setup that are waiting to start and, based on what they need and where they can run, it gets the best computers to run them, making sure you&amp;#39;re using your resources well and not spending too much.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&amp;#39;s Cluster Autoscaler, and How Does It Work on AWS?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler is another popular open-source tool that lots of people use to automatically change the size of their Kubernetes setup on AWS. It&amp;#39;s looked after by a special group in the Kubernetes community. Its main job is to make sure you have enough computers in your setup to run all your apps, but also to get rid of computers that aren&amp;#39;t doing much so you don&amp;#39;t waste resources.&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler works with groups of computers, usually by talking to AWS&amp;#39;s Auto Scaling Groups (ASGs) or Managed Node Groups (MNGs). It constantly checks your Kubernetes setup for apps that can&amp;#39;t start because there aren&amp;#39;t enough resources. If it finds some, it makes the cluster bigger by telling the ASGs to add more computers. It also makes the cluster smaller by finding computers that haven&amp;#39;t been used much for a while and trying to remove them after moving their apps to other computers safely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How Are Their Ways of Getting Computers and Scaling Different?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main difference between Karpenter and Cluster Autoscaler is how they&amp;#39;re set up and how they handle getting new computers and making the cluster bigger or smaller. Karpenter thinks about things from the app&amp;#39;s point of view. It talks directly to AWS to get individual computers exactly when and where they&amp;#39;re needed based on what the apps are asking for. This means it can get computers that are just the right size for the job. Cluster Autoscaler, on the other hand, thinks about groups of computers. It works with ASGs or MNGs, which are groups of computers that are all set up the same way. When it needs to make the cluster bigger, it just tells these groups to add more computers.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Karpenter&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cluster Autoscaler&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;How it Sees Things&lt;/td&gt;
&lt;td&gt;App-focused, manages individual computers&lt;/td&gt;
&lt;td&gt;Group-focused, manages groups of computers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How it Adds Computers&lt;/td&gt;
&lt;td&gt;Gets computers based on what apps need, can combine apps on fewer nodes&lt;/td&gt;
&lt;td&gt;Tells groups of computers to get bigger, removes computers that aren&amp;#39;t being used much&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manages Computer Groups?&lt;/td&gt;
&lt;td&gt;No, manages individual computers&lt;/td&gt;
&lt;td&gt;Yes, manages groups of computers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How Detailed is the Scaling&lt;/td&gt;
&lt;td&gt;Very detailed, based on what each app needs&lt;/td&gt;
&lt;td&gt;Works at the group level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How Much it Knows AWS&lt;/td&gt;
&lt;td&gt;Knows AWS very well&lt;/td&gt;
&lt;td&gt;Can work with different cloud providers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Karpenter watches the Kubernetes system for apps that are waiting to start but can&amp;#39;t because there aren&amp;#39;t enough resources. Then, it looks at what these apps need (like processing power and memory) and where they can run (based on rules you set) to get new computers that fit those needs exactly. When computers aren&amp;#39;t needed anymore, Karpenter can get rid of them. It even has smart ways to combine apps onto fewer computers to save money by finding and removing computers that aren&amp;#39;t being used much.&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler works by looking for apps that can&amp;#39;t start or computers in its groups that aren&amp;#39;t being used much. When it needs to make the cluster bigger, it usually just adds new computers to the group based on how the group was set up in the first place.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which One is Faster at Getting New Computers?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When it comes to how fast they can get new computers up and running, Karpenter usually wins. Because it talks directly to AWS, it can often get new computers ready in less than a minute. This quick turnaround means Karpenter can react really fast when your apps need more power, and it helps keep things running smoothly even when there are sudden spikes in activity.&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler, because it works through ASGs, has an extra step in the process, which can make it a bit slower to get new computers. While it does watch for apps that need more resources and adds computers, the time it takes for ASGs to get those computers ready can be a little longer than Karpenter&amp;#39;s direct approach. If your apps need more power right away, Karpenter&amp;#39;s speed can be a big advantage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which One is Better at Saving Money and Using Resources Wisely?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Karpenter is generally better at saving money and using your computer resources effectively. Because it can get computers that are just the right size for the apps that need them, you&amp;#39;re less likely to end up paying for computer power you&amp;#39;re not using. Plus, Karpenter can combine apps onto fewer computers and get rid of the ones that aren&amp;#39;t doing much, which helps cut down on costs even more. It&amp;#39;s also good at packing apps tightly onto computers to make the most of the resources available. And because it can choose from lots of different types of computers, it can pick the ones that give you the best bang for your buck for what your apps need.&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler, on the other hand, adds computers based on groups that are set up beforehand. This might mean you end up with bigger computers than you actually need if the sizes in the group don&amp;#39;t match what your apps are asking for. While it can also remove computers that aren&amp;#39;t being used much, how well it saves you money depends a lot on how you set it up in the first place and how similar the demands of your apps are within each group.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How Much Can You Change and Customize Them?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Karpenter gives you more ways to change and customize things compared to Cluster Autoscaler. With its NodePool and EC2NodeClass settings, you can really fine-tune what your computers look like. You can choose specific types of computers, different kinds of processors (like AMD or ARM), operating systems, and whether to use regular or cheaper, but sometimes interrupted, Spot Instances. You can even tell it to prefer certain types of computers. Plus, Karpenter has lots of options for how it scales, including smart ways to combine apps, settings for how long computers should last before being replaced, and ways to make sure your computers stay the way you want them. Karpenter also pays attention to rules you set about how many apps can be disrupted at once, so you have control over how quickly it can make changes.&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler works with groups of computers that are set up beforehand, so you don&amp;#39;t have as much flexibility in choosing computer types within a single group. If you want to add new types, you often have to make changes to your initial setup. While Cluster Autoscaler does have some settings you can tweak, like how often it checks for changes and how long it waits before removing computers, it generally doesn&amp;#39;t give you as much detailed control as Karpenter. If you have multiple groups of computers, Cluster Autoscaler has some strategies to decide which group to make bigger, giving you some say in how new capacity is added.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How Do They Handle Spot Instances?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Karpenter is really good with Spot Instances, which can save you a lot of money. You can easily tell Karpenter to use Spot Instances first and then switch to regular ones if Spot capacity isn&amp;#39;t available. It even tries to pick Spot Instances that are cheap but also less likely to be interrupted. Karpenter can also replace one Spot Instance with another cheaper one without going back to regular instances. Plus, it knows how to handle notifications about Spot Instances being interrupted. When a Spot Instance is about to be stopped, Karpenter can automatically move the apps running on it to new computers.&lt;/p&gt;
&lt;p&gt;While Cluster Autoscaler can use Spot Instances, it usually takes more work to set up within the groups of computers you manage. To handle Spot interruptions smoothly, you might need to use extra tools like the AWS Node Termination Handler. Also, if Spot Instance capacity isn&amp;#39;t available, switching to regular instances might not be as seamless as with Karpenter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How Well Do They Fit with AWS and Other Kubernetes Tools?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Karpenter works really well with AWS, using services like EC2, IAM (for managing permissions), and EventBridge (for Spot Instance alerts) to make scaling on AWS easy. While it started with a focus on AWS, it&amp;#39;s also designed to work with other cloud providers like Azure and Alibaba Cloud.&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler can work with many different cloud providers, including AWS, Google Cloud, and Azure. Both tools work with other important Kubernetes features like the Horizontal Pod Autoscaler (HPA) and Vertical Pod Autoscaler (VPA), so you can have a complete system for scaling both your apps and the computers they run on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How Easy Are They to Set Up and Manage?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Karpenter is generally easier to set up and manage, especially if you&amp;#39;re already using AWS. You can usually install it easily using Helm charts. You configure it mainly through Kubernetes settings, which feels natural if you&amp;#39;re used to Kubernetes. One of the big pluses of Karpenter is that you don&amp;#39;t have to manage lots of pre-defined groups of computers, which simplifies things when you have different kinds of apps running. Karpenter also has features like automatically replacing older computers and upgrading them, which can make managing your setup easier.&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler, while it&amp;#39;s been around for a while and lots of people use it, can take more steps to set up. This includes setting up AWS Auto Scaling Groups, giving the autoscaler permission to talk to AWS, and then installing the Cluster Autoscaler itself in your Kubernetes setup. If you have many different kinds of apps, managing multiple groups of computers with specific settings can also make things more complicated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What About Performance and Potential Problems?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Both Karpenter and Cluster Autoscaler are designed to perform well, but they can have different kinds of issues. Karpenter might have trouble with really big setups or when apps are being created and deleted very quickly. Some users have mentioned that you don&amp;#39;t have a lot of control over how it balances things across different availability zones, which could be a concern for apps that need to be very fast. Also, the computer usage numbers from Karpenter don&amp;#39;t show up directly in AWS&amp;#39;s CloudWatch, so you might need to use other tools to keep an eye on things.&lt;/p&gt;
&lt;p&gt;Cluster Autoscaler has been tested to work with up to 1000 computers, but it might slow down if you have a lot more than that. While it&amp;#39;s usually fast enough, the time it takes to add new computers can be a problem for apps that need to scale up immediately when demand changes quickly.&lt;/p&gt;
&lt;p&gt;Karpenter is especially good for apps that have changing needs and different computer requirements, like when you&amp;#39;re processing a lot of data or doing machine learning. Cluster Autoscaler might not be as good for apps that change a lot or need specific types of computers that aren&amp;#39;t already set up in its groups.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Frequently Asked Questions:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the main differences between Karpenter and Cluster Autoscaler?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Karpenter directly gets computers that are the right size for your apps and
  can combine apps on fewer computers, making it faster and more efficient.
  Cluster Autoscaler changes the size of groups of computers based on apps that
  are waiting to start and computers that aren&amp;#39;t being used much.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;Which one is better for saving money?&quot;&gt;
  Karpenter is usually better at saving money because it gets computers that are
  just the right size and can combine apps to use resources more efficiently.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Can I use them both at the same time?&quot;&gt;
  While you could technically do it, it&apos;s generally not a good idea to run both
  Karpenter and Cluster Autoscaler on the same setup because they might
  interfere with each other and cause unexpected scaling.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Which one is easier to set up?&quot;&gt;
  Karpenter is often simpler to set up, especially if you&apos;re using AWS, because
  it uses standard Kubernetes tools.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Which one performs better?&quot;&gt;
  Karpenter typically performs better, especially when it comes to how quickly
  it can react to changes in your apps&apos; needs.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;What are the downsides of each?&quot;&gt;
  Karpenter doesn&apos;t have as much built-in support for working with different
  cloud providers and you might not have as much control over some things like
  where it puts the computers. Cluster Autoscaler can be slower to react and
  might end up getting bigger computers than you need.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;When should I choose Karpenter over Cluster Autoscaler, and when should I choose Cluster Autoscaler?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Pick Karpenter if you want faster scaling, to save more money, and if you need
  more flexibility with the types of computers you use on AWS. Go with Cluster
  Autoscaler if you need to work with different cloud providers or if you prefer
  the more predictable way it manages groups of computers.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;Does Karpenter work with more than just AWS?&quot;&gt;
  Yes, while it started with AWS, Karpenter is designed to work with other cloud
  providers too, and it now supports Azure and Alibaba Cloud, with the
  possibility of adding more in the future.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does Karpenter handle Spot Instances being interrupted?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Karpenter knows how to deal with notifications about Spot Instances being
  stopped. It can automatically move the apps to new computers and then shut
  down the interrupted ones.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Is Karpenter ready to be used for important systems?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Yes, Karpenter version 1.0 has been released and is considered ready for
  production use.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do I switch from Cluster Autoscaler to Karpenter?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Usually, you&amp;#39;d start by installing Karpenter and setting up its
  configurations, and then you&amp;#39;d remove Cluster Autoscaler.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;Where can I find more information and help?&quot;&gt;
  You can find lots of details on the official Karpenter website (karpenter.sh)
  and in the Kubernetes Autoscaling group&apos;s information, as well as in AWS&apos;s
  documentation.
&lt;/Accordion&gt;&lt;p&gt;&lt;strong&gt;Wrapping Up: Picking What&amp;#39;s Right for Your Kubernetes Scaling on AWS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Both Karpenter and Cluster Autoscaler are great tools for automatically scaling your Kubernetes setup on AWS, but they&amp;#39;re better for different situations. Karpenter is fast, flexible, and can save you money, making it a good fit if you&amp;#39;re really focused on using AWS and want a more modern way to handle scaling. It&amp;#39;s a solid choice if you need to scale quickly, want a lot of control over the types of computers you use (especially Spot Instances), and want to keep things simple by not managing lots of computer groups.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Karpenter&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cluster Autoscaler&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Speed of Adding Computers&lt;/td&gt;
&lt;td&gt;Faster&lt;/td&gt;
&lt;td&gt;Slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost Savings&lt;/td&gt;
&lt;td&gt;Usually better because it gets the right size and combines apps well&lt;/td&gt;
&lt;td&gt;Depends on how you set it up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexibility&lt;/td&gt;
&lt;td&gt;Very flexible with lots of settings&lt;/td&gt;
&lt;td&gt;Less flexible, works with pre-set computer groups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handling Spot Instances&lt;/td&gt;
&lt;td&gt;Excellent, built-in support for interruptions&lt;/td&gt;
&lt;td&gt;Needs more manual setup and extra tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works with Other Clouds?&lt;/td&gt;
&lt;td&gt;Growing support (AWS, Azure, Alibaba Cloud)&lt;/td&gt;
&lt;td&gt;Works with many different cloud providers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How Easy to Manage&lt;/td&gt;
&lt;td&gt;Easier, more automatic&lt;/td&gt;
&lt;td&gt;More manual setup needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reacts to Changes&lt;/td&gt;
&lt;td&gt;Reacts very quickly to changes in app needs&lt;/td&gt;
&lt;td&gt;Checks periodically, might be slower to react to sudden changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Combining Apps on Computers&lt;/td&gt;
&lt;td&gt;Advanced, can even combine Spot Instances&lt;/td&gt;
&lt;td&gt;Basic, focuses on removing empty or underused computers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Cluster Autoscaler is still a good, reliable option, especially if you need to work with different cloud providers or if you like the more traditional way of managing computer power through pre-defined groups. In the end, the best tool for you depends on what you need and what&amp;#39;s important for your Kubernetes setup on AWS. Think about what your apps do, how they need to scale, and what your goals are for saving money. It&amp;#39;s probably a good idea to try both tools out in a test environment to see which one fits best with your setup and how you like to work.&lt;/p&gt;
&lt;h4&gt;References&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://karpenter.sh/&quot;&gt;Karpenter Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/eks/latest/best-practices/karpenter.html&quot;&gt;AWS Documentation: Karpenter on Amazon EKS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/eks/latest/userguide/autoscaling.html&quot;&gt;AWS Documentation: Cluster Autoscaler on Amazon EKS&lt;/a&gt; (covers Cluster Autoscaler)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/aws/introducing-karpenter-an-open-source-high-performance-kubernetes-cluster-autoscaler/&quot;&gt;Introducing Karpenter – An Open-Source High-Performance Kubernetes Cluster Autoscaler | AWS News Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler&quot;&gt;Kubernetes Autoscaler GitHub Repository (for Cluster Autoscaler)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.perfectscale.io/blog/karpenter-vs-cluster-autoscaler&quot;&gt;Karpenter vs Cluster Autoscaler: The Ultimate Guide - Perfect Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spacelift.io/blog/karpenter-vs-cluster-autoscaler&quot;&gt;Karpenter vs. Cluster Autoscaler - Kubernetes Scaling Tools - Spacelift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cncf.io/blog/2024/05/22/aws-karpenter-vs-kubernetes-cluster-autoscaler-choosing-the-right-auto-scaling-tool/&quot;&gt;AWS Karpenter vs Kubernetes Cluster Autoscaler: choosing the right auto-scaling tool | CNCF Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://karpenter.sh/docs/concepts/&quot;&gt;Karpenter Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://karpenter.sh/docs/getting-started/migrating-from-cas/&quot;&gt;Migrating from Cluster Autoscaler to Karpenter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://karpenter.sh/docs/faq/&quot;&gt;Karpenter FAQs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md&quot;&gt;Cluster Autoscaler FAQ (Kubernetes GitHub)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/containers/optimizing-your-kubernetes-compute-costs-with-karpenter-consolidation/&quot;&gt;Optimizing your Kubernetes compute costs with Karpenter consolidation | AWS Containers Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/containers/using-amazon-ec2-spot-instances-with-karpenter/&quot;&gt;Using Amazon EC2 Spot Instances with Karpenter | AWS Containers Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cncf.io/blog/2024/11/06/karpenter-v1-0-0-beta/&quot;&gt;What Karpenter v1.0.0 means for Kubernetes autoscaling | CNCF Blog&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Kubernetes</category><category>Cloud Computing</category><category>AWS</category><category>Autoscaling</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0080-karpenter-vs-cluster-autoscaler-aws-kubernetes-scaling/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Unlocking the Secrets: HashiCorp Vault vs. AWS Secrets Manager vs. SOPS - Which Reigns Supreme</title><link>https://mkabumattar.com/blog/post/secrets-management-vault-secrets-manager-sops/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/secrets-management-vault-secrets-manager-sops/</guid><description>Compare HashiCorp Vault, AWS Secrets Manager, and SOPS for secrets management. Understand their features, security, automation, and best practices to choose the right tool.</description><pubDate>Sun, 25 May 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let&amp;#39;s face it, in today&amp;#39;s tech world, keeping sensitive info safe – we&amp;#39;re talking about those digital keys like API keys and passwords – is a big deal. They&amp;#39;re what let you into important systems and data. But with everything living in different places now, from clouds to your own servers, picking the right tool to manage these secrets can feel like a real puzzle. You&amp;#39;ve probably heard of HashiCorp Vault, AWS Secrets Manager, and SOPS. They&amp;#39;re some of the big names out there. So, what&amp;#39;s the deal with each of them? This post is going to break down these three tools in a way that&amp;#39;s easy to understand, looking at what they&amp;#39;re good at, where they might fall short, and when you&amp;#39;d want to use each one. Hopefully, by the end, you&amp;#39;ll have a better idea of which one is the best fit for your team.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why Bother with Secrets Management Anyway? Spotting the Hidden Dangers of Messing It Up.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;If you&amp;#39;re not careful with how you handle secrets, you&amp;#39;re basically leaving the door wide open for trouble. Think about it: if you just type passwords right into your app&amp;#39;s code or keep API keys in plain text files, it&amp;#39;s like putting a &amp;quot;steal me&amp;quot; sign on them. And if those secrets get out, it can be a nightmare. We&amp;#39;re talking about people getting into your sensitive data, your services going down, or even massive data breaches that can get you in serious trouble with the rules. This isn&amp;#39;t just some made-up threat; it happens in the real world, which is why getting secrets management right is so important.&lt;/p&gt;
&lt;p&gt;Having a good system for managing secrets isn&amp;#39;t just about avoiding the bad stuff, though. It actually gives you a bunch of other benefits. By keeping all your sensitive info in one secure place, you can really boost your overall security with things like encryption and tight controls on who can see what. Plus, a lot of these tools can automate things, making your life easier by handling tasks like changing passwords regularly and getting them where they need to go. This not only saves you time but also helps you follow the rules by keeping track of who did what and making sure you&amp;#39;re meeting different requirements. A solid plan also helps you avoid &amp;quot;secret sprawl,&amp;quot; where you have sensitive credentials scattered all over the place, making them a pain to keep track of.&lt;/p&gt;
&lt;p&gt;There are some basic things you should always do when it comes to secrets management. The idea of &amp;quot;least privilege&amp;quot; is key – only give people and applications the access they absolutely need, so if something does go wrong, the damage is limited. Changing your secrets regularly, especially the really important ones, means that if a secret does get compromised, it won&amp;#39;t be useful for long. Keeping everything in one central spot gives you a clear view of all your secrets. And finally, keeping logs of who&amp;#39;s accessing what helps you keep an eye on things and figure out what happened if there&amp;#39;s a security problem.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;HashiCorp Vault: Could This Be Your Security Superhero?&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What&amp;#39;s HashiCorp Vault all about, and why is it special?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;HashiCorp Vault is a really handy open-source tool that&amp;#39;s designed to help you manage secrets, encrypt your data, and handle who gets special access to things. It&amp;#39;s got a lot of features aimed at keeping your sensitive stuff safe, no matter where it lives. Basically, Vault gives you a secure, central place to store things like API keys, passwords, and certificates. To make sure no one can read them, Vault scrambles this data before it saves it, so even if someone gets into the storage, the secrets are still protected. For data that&amp;#39;s moving around, Vault has something called the Transit Secrets Engine, which lets you encrypt data as a service.&lt;/p&gt;
&lt;p&gt;One of the coolest things about Vault is that it can create secrets that only last for a short time. Instead of having the same passwords hanging around forever, Vault can make temporary ones just for a specific client, and they often expire quickly. This makes things much more secure because even if someone manages to grab a secret, it won&amp;#39;t be valid for long. Access to these secrets is tightly controlled by rules you set up using Access Control Lists (ACLs). Vault works on a &amp;quot;you can&amp;#39;t unless we say so&amp;quot; model, where you have to specifically grant permission through these rules. These rules, written in a language called HCL, tell Vault exactly what different users and applications are allowed to do with different secrets.&lt;/p&gt;
&lt;p&gt;For keeping track of things, Vault logs every single request and response. This detailed record is super important for security monitoring, following the rules, and figuring out what happened if there&amp;#39;s an incident. Plus, Vault&amp;#39;s Transit Secrets Engine can do encryption and decryption on data as it passes through without actually storing the data itself. This gives you a central way for your apps to handle encryption without having to manage the keys themselves. Vault also uses an identity-based security approach, where it checks who you are before letting you do anything, and it works with different ways of proving your identity and can connect to other identity systems.&lt;/p&gt;
&lt;p&gt;Under the hood, Vault has a few main parts. There&amp;#39;s an API that everything talks to, a storage area for saving data (which Vault treats as unsafe and encrypts everything before putting it there) and a security barrier that protects the core functions. When a Vault server starts up, it&amp;#39;s in a &amp;quot;sealed&amp;quot; state and needs to be &amp;quot;unsealed&amp;quot; by providing a set of special keys before it can do anything. This unsealing process unlocks the main encryption key, which then unlocks the key that protects all the data.&lt;/p&gt;
&lt;p&gt;Another big plus for Vault is its &amp;quot;pluggable&amp;quot; design. This means it can connect to a lot of different platforms and services through its various components, like different ways to log in, audit logs, and secrets engines. This makes Vault very adaptable to all sorts of different setups.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;When does HashiCorp Vault really shine?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;HashiCorp Vault is a real lifesaver in a few key situations. Because it doesn&amp;#39;t care which cloud you&amp;#39;re using and can connect to so many things, it&amp;#39;s perfect for managing secrets in complex setups that use multiple cloud providers and even have a mix of cloud and on-premise resources. If security is your top concern, Vault&amp;#39;s ability to create temporary, short-lived credentials on demand really cuts down on the risk that comes with having long-lasting secrets.&lt;/p&gt;
&lt;p&gt;Also, Vault is great when you need really specific control over who can access secrets and you need strong rules to manage that access. Its policy-based system lets you define very precise permissions, making sure only the right people or applications can see certain secrets. If you want to offer encryption as a service to your applications, Vault&amp;#39;s Transit Secrets Engine is the way to go, giving you a central and secure way to encrypt and decrypt data without your apps having to deal with the encryption keys directly. On top of that, Vault can even act like your own internal Certificate Authority, creating and managing SSL/TLS certificates for your internal services.&lt;/p&gt;
&lt;p&gt;Vault&amp;#39;s strengths really lie in its wide range of features and how well it can adapt to different and complicated environments. Its ability to work across different clouds is a big advantage. The fact that it has a large community and lots of integrations makes it even more useful. Advanced security features like dynamic secrets and encryption as a service are a huge plus. And finally, its strong focus on rules for access control gives you the detailed control you need to manage sensitive information securely.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What should you think about before picking Vault?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Even though Vault has a lot going for it, there are a few things to consider before you jump in. Setting up and getting Vault running, especially in a way that&amp;#39;s highly available for production, can be more complicated than using a managed service. If you host Vault yourself, you also have to deal with more operational work, like managing the underlying servers, doing upgrades, and setting up monitoring. People who are new to Vault might also find it takes a while to really understand how it works, its architecture, and its policy language. While there&amp;#39;s a free, open-source version, a lot of the more advanced features that big companies need, like replication, cost money with a commercial license. So, while Vault is a powerful tool, you&amp;#39;ll probably need some dedicated expertise and resources to get it working well and keep it running, and the cost can be a big factor if you&amp;#39;re on a tight budget.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;AWS Secrets Manager: Your Cloud&amp;#39;s Built-In Security Buddy?&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What is AWS Secrets Manager, and how well does it play with other AWS services?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;AWS Secrets Manager is a service from Amazon Web Services that&amp;#39;s all about helping you manage, get, and regularly change your sensitive information throughout its life. It makes it easier to keep secrets safe within the AWS world. One of the main things it does is securely store secrets, encrypting them when they&amp;#39;re just sitting there using AWS Key Management Service (KMS). This gives your sensitive data a strong layer of protection.&lt;/p&gt;
&lt;p&gt;Secrets Manager can also automatically change passwords for several AWS database services, like Amazon RDS, Amazon Redshift, and Amazon DocumentDB. Plus, you can make it work with other types of secrets by using AWS Lambda functions. Access to the secrets you store in Secrets Manager is controlled using AWS Identity and Access Management (IAM) policies, which is a familiar and robust way for AWS users to manage who can do what.&lt;/p&gt;
&lt;p&gt;A big advantage of Secrets Manager is how well it works with a ton of other AWS services. This tight connection makes it simpler to manage and access secrets for your applications and services that are already running on AWS. For keeping track of things and following the rules, every interaction with Secrets Manager is logged in AWS CloudTrail, giving you a detailed record of who accessed what and when. Secrets Manager also lets you automatically copy your secrets to multiple AWS regions, which is great for making sure your secrets are always available and for disaster recovery.&lt;/p&gt;
&lt;p&gt;For companies that mostly or only use AWS services, Secrets Manager is a built-in solution that&amp;#39;s designed to be simple and easy to use. Because it&amp;#39;s managed by AWS, you don&amp;#39;t have to worry as much about the behind-the-scenes stuff.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;When is AWS Secrets Manager the best choice?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;AWS Secrets Manager is often the go-to option for organizations that rely heavily or exclusively on AWS services. If most of your infrastructure is on AWS, Secrets Manager provides a convenient and well-integrated way to handle your sensitive credentials. It&amp;#39;s especially useful when you need to automatically change database passwords for AWS services it supports directly, like RDS, Redshift, and DocumentDB, because this feature is built right into the service.&lt;/p&gt;
&lt;p&gt;Teams that want a fully managed service where AWS takes care of the servers, scaling, and upkeep will find AWS Secrets Manager appealing. Also, if you have applications running on AWS that need to get secrets on the fly, Secrets Manager integrates smoothly with the AWS SDKs, making it easy for developers to fetch the credentials they need.&lt;/p&gt;
&lt;p&gt;The strengths of AWS Secrets Manager are in how easy it is to set up and use within the AWS environment. As a managed service, it takes a lot of the operational burden off your shoulders. The automatic password rotation for key AWS database services simplifies security management. And finally, because it uses the familiar AWS IAM for access control, it&amp;#39;s easy for organizations already using AWS to manage who can see their secrets.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What might make you look beyond AWS Secrets Manager?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Even though it&amp;#39;s super handy for AWS users, there are some limits and things to think about that might make you consider other options besides AWS Secrets Manager. Compared to HashiCorp Vault, Secrets Manager isn&amp;#39;t as flexible and doesn&amp;#39;t have as many features, especially if you have more complex needs or a mix of different environments. As the name suggests, Secrets Manager is really focused on the AWS ecosystem, so it&amp;#39;s not the best fit if you have a lot of stuff outside of AWS, like in a multi-cloud or hybrid setup.&lt;/p&gt;
&lt;p&gt;The way AWS Secrets Manager charges, which is based on how many secrets you store and how many times you access them, can get expensive if you have a lot of secrets or your applications access them very frequently. Also, while it can automatically change passwords for some AWS services, if you need to do that for things not on AWS, you have to create and manage your own AWS Lambda functions, which can make things more complicated. So, while it&amp;#39;s a convenient choice for many AWS users, its limitations in flexibility, support for different clouds, and potential cost if you have a lot of secrets can be downsides for organizations with more diverse or larger-scale needs.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;SOPS: Keeping Secrets Safe Right in Your Code?&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;What is SOPS, and how does it handle secrets differently?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;SOPS (Secrets OPerationS) is a free tool you can use from your command line that takes a different approach to managing secrets. It lets you encrypt sensitive information directly inside your files, like YAML, JSON, and ENV files. Unlike traditional secrets managers that keep everything in one central vault, SOPS focuses on scrambling the secret parts of your configuration files while leaving the rest readable. This makes it easier to keep track of changes to your configurations in systems like Git.&lt;/p&gt;
&lt;p&gt;One of the great things about SOPS is that it can use different ways to encrypt your secrets, including popular Key Management Services (KMS) like AWS KMS, GCP KMS, and Azure Key Vault, as well as simpler methods that work offline, like age and PGP. This means you can pick the encryption method that works best with your security rules and your setup. SOPS is especially useful for teams that follow GitOps practices, where your Git repository is the main place where all your application code and infrastructure configurations, including secrets, live.&lt;/p&gt;
&lt;p&gt;By putting secrets management right into the development process and version control, SOPS offers a different way of thinking about security compared to having a separate secrets management platform. It lets developers handle secrets alongside their code and configurations in a secure way.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;When is SOPS a really good option?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;SOPS becomes a really attractive option for teams that are doing GitOps and managing their infrastructure as code. For these teams, SOPS provides a way to securely store secrets right in their Git repositories, making sure that any sensitive data they put into version control stays encrypted and protected. Organizations that like to keep their secrets alongside their application settings will also find SOPS useful, as it lets them store both in the same place.&lt;/p&gt;
&lt;p&gt;Plus, SOPS is a great choice if you need to work with multiple cloud providers or want the flexibility of using offline encryption methods like age or PGP. Its ability to work with different encryption systems gives you the adaptability you need for various environments and security needs. A big advantage of SOPS is that it lets you store encrypted secrets in version control, so you can see how they&amp;#39;ve changed over time. It supports a wide range of encryption methods and key management systems, giving you the freedom to choose what&amp;#39;s best for you. SOPS also works well with popular GitOps tools like Flux and ArgoCD, which can automatically decrypt secrets managed by SOPS when you&amp;#39;re deploying your applications. Finally, because only the secret parts of your configuration files are encrypted, the overall structure of the files remains readable, making them easier to understand and manage.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;What are some of the downsides of using SOPS?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While SOPS has a lot of good things going for it, there are also some trade-offs to think about. Because SOPS encrypts secrets at the file level, it&amp;#39;s really important to manage the encryption keys carefully to prevent unauthorized access or losing them. Unlike dedicated secrets managers, SOPS doesn&amp;#39;t have a built-in way to automatically change secrets regularly; if you need to do that, you&amp;#39;ll have to set it up yourself using other tools or scripts. Also, SOPS doesn&amp;#39;t have a central management interface or API like Vault or AWS Secrets Manager. It&amp;#39;s mainly a command-line tool, which might not be ideal for everyone or every situation. The security of your secrets with SOPS really depends on how strong the encryption method you choose is and how secure you keep the keys. So, while SOPS is a handy and flexible tool for GitOps workflows, it puts more responsibility on you for managing keys and rotating secrets, and it might not be the best fit if you&amp;#39;re looking for a centralized secrets management platform with a lot of built-in automation.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Vault vs. Secrets Manager vs. SOPS: A Practical Look.&lt;/strong&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;Feature-by-Feature Breakdown:&lt;/strong&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;HashiCorp Vault&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AWS Secrets Manager&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;SOPS (Secrets OPerationS)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strong; encryption at rest/in transit, ACLs, dynamic secrets, audit logging, key management, identity-based&lt;/td&gt;
&lt;td&gt;Strong; encryption at rest/in transit, IAM, automatic rotation, audit logging&lt;/td&gt;
&lt;td&gt;Strong; file-based encryption, relies on backend KMS/PGP/age&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Built-in dynamic secrets, API-driven rotation&lt;/td&gt;
&lt;td&gt;Automatic rotation for AWS services, Lambda for others&lt;/td&gt;
&lt;td&gt;Requires external automation for rotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Extensive; multi-cloud, on-premise, Kubernetes, etc.&lt;/td&gt;
&lt;td&gt;AWS ecosystem&lt;/td&gt;
&lt;td&gt;GitOps tools, KMS providers (AWS, GCP, Azure), PGP, age&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can be complex initially, steeper learning curve&lt;/td&gt;
&lt;td&gt;Straightforward within AWS ecosystem&lt;/td&gt;
&lt;td&gt;Relatively easy to use for file encryption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open-source (limited), Enterprise (licensed)&lt;/td&gt;
&lt;td&gt;Pay-per-secret, per API call&lt;/td&gt;
&lt;td&gt;Free and open-source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi/hybrid cloud, complex requirements, dynamic secrets, encryption as a service&lt;/td&gt;
&lt;td&gt;AWS-centric environments, automated rotation for AWS services&lt;/td&gt;
&lt;td&gt;GitOps workflows, secrets in version control&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;&lt;strong&gt;Use Case Scenarios:&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scenario 1:&lt;/strong&gt; A startup heavily invested in AWS needing basic secret storage and rotation for RDS. &lt;strong&gt;Recommendation:&lt;/strong&gt; AWS Secrets Manager - its ease of use and native integration with AWS make it ideal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scenario 2:&lt;/strong&gt; A large enterprise with a hybrid cloud infrastructure requiring dynamic secrets, fine-grained policies, and encryption as a service. &lt;strong&gt;Recommendation:&lt;/strong&gt; HashiCorp Vault - its versatility and advanced features are well-suited for complex environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scenario 3:&lt;/strong&gt; A development team practicing GitOps on Kubernetes and needing to store secrets securely in their Git repository. &lt;strong&gt;Recommendation:&lt;/strong&gt; SOPS - its file-based encryption and GitOps focus align perfectly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scenario 4:&lt;/strong&gt; An organization needing to manage secrets across multiple cloud providers with a centralized solution. &lt;strong&gt;Recommendation:&lt;/strong&gt; HashiCorp Vault - its cloud-agnostic nature provides a unified approach.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions (FAQ):&lt;/strong&gt;&lt;/h2&gt;
&lt;Accordion client:load title=&quot;Should I store secrets in environment variables?&quot;&gt;
  Generally not recommended for production due to security risks; use a
  dedicated secrets management solution that offers encryption and access
  control.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;What is the best way to handle API keys?&quot;&gt;
  Store them securely in a secrets manager and retrieve them dynamically within
  your application code; avoid hardcoding them in the codebase or configuration
  files.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;How often should I rotate my secrets?&quot;&gt;
  The frequency depends on the sensitivity of the secret and your organization&apos;s
  security policies; automate rotation as much as possible, especially for
  critical credentials.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the key differences between static and dynamic secrets?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Static secrets are long-lived credentials that are stored and retrieved as
  needed, while dynamic secrets are generated on demand with short lifespans,
  improving security by reducing the window of opportunity for misuse.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;Is it safe to store encrypted secrets in Git?&quot;&gt;
  Yes, if using a tool like SOPS with strong encryption and proper key
  management practices; ensure that the decryption keys are not stored in the
  same repository.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the cost implications of using these tools?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  AWS Secrets Manager charges per secret stored and per API call; HashiCorp
  Vault has an open-source version and a licensed Enterprise version with
  different pricing models; SOPS is free and open-source, but the cost of the
  underlying KMS should be considered.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;How do these tools integrate with Kubernetes?&quot;&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HashiCorp Vault:&lt;/strong&gt; Offers a Kubernetes Secrets engine to synchronize Vault
secrets with Kubernetes secrets and a Vault Agent Injector to automatically
inject secrets into pods.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS Secrets Manager:&lt;/strong&gt; Can be integrated with
Kubernetes using the AWS Secrets Manager Controller for Kubernetes (ASCP) or
External Secrets Operator (ESO) to fetch secrets from Secrets Manager and
create Kubernetes secrets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SOPS:&lt;/strong&gt; Integrates with Kubernetes GitOps tools
like Flux and ArgoCD, allowing them to decrypt SOPS-encrypted secrets during
deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Accordion&gt;&lt;h2&gt;&lt;strong&gt;Conclusion: Making the Right Choice for Your Secrets - It&amp;#39;s About What You Need, Not Just What It Does.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;So, to wrap things up, HashiCorp Vault, AWS Secrets Manager, and SOPS each bring something different to the table when it comes to managing secrets. Vault is the powerhouse with lots of features, great for complex setups that span multiple clouds and need things like temporary secrets and really specific access rules. AWS Secrets Manager is your handy friend if you&amp;#39;re mostly or only on AWS, offering simplicity and automatic password changes for key AWS services. SOPS takes a more code-centric approach, letting you encrypt secrets right in your configuration files, which is perfect if you&amp;#39;re into GitOps.&lt;/p&gt;
&lt;p&gt;The &amp;quot;best&amp;quot; tool really isn&amp;#39;t about which one has the most bells and whistles. It comes down to what your organization actually needs. Think about how much you&amp;#39;re using the cloud, how complicated your setup is, how big your team is, and what your security and compliance requirements are. Keeping your secrets safe is a fundamental part of a good security plan, and picking the right tool is a big step in making your infrastructure more secure and efficient.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;The Essential Guide to Secrets Management | Akeyless, accessed on May 9, 2025, &lt;a href=&quot;https://www.akeyless.io/blog/the-essential-guide-to-secrets-management/&quot;&gt;https://www.akeyless.io/blog/the-essential-guide-to-secrets-management/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Secrets Management &amp;amp; Security: Hashicorp Vault - DEV Community, accessed on May 9, 2025, &lt;a href=&quot;https://dev.to/s3cloudhub/secrets-management-security-hashicorp-vault-4032&quot;&gt;https://dev.to/s3cloudhub/secrets-management-security-hashicorp-vault-4032&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Security Model | Vault - HashiCorp Developer, accessed on May 9, 2025, &lt;a href=&quot;https://developer.hashicorp.com/vault/docs/internals/security&quot;&gt;https://developer.hashicorp.com/vault/docs/internals/security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;HashiCorp Vault | Identity-based secrets management, accessed on May 9, 2025, &lt;a href=&quot;https://hashicorp.com/products/vault&quot;&gt;https://hashicorp.com/products/vault&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Access controls with Vault policies - HashiCorp Developer, accessed on May 9, 2025, &lt;a href=&quot;https://developer.hashicorp.com/vault/tutorials/policies/policies&quot;&gt;https://developer.hashicorp.com/vault/tutorials/policies/policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Data protection in AWS Secrets Manager, accessed on May 9, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/secretsmanager/latest/userguide/data-protection.html&quot;&gt;https://docs.aws.amazon.com/secretsmanager/latest/userguide/data-protection.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Secrets Manager, accessed on May 9, 2025, &lt;a href=&quot;https://aws.amazon.com/secrets-manager/&quot;&gt;https://aws.amazon.com/secrets-manager/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Log AWS Secrets Manager events with AWS CloudTrail - AWS Documentation, accessed on May 9, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/secretsmanager/latest/userguide/monitoring-cloudtrail.html&quot;&gt;https://docs.aws.amazon.com/secretsmanager/latest/userguide/monitoring-cloudtrail.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Secrets Manager Pricing, accessed on May 9, 2025, &lt;a href=&quot;https://aws.amazon.com/secrets-manager/pricing/&quot;&gt;https://aws.amazon.com/secrets-manager/pricing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SOPS: Secrets OPerationS, accessed on May 9, 2025, &lt;a href=&quot;https://getsops.io/&quot;&gt;https://getsops.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;getsops/sops: Simple and flexible tool for managing secrets - GitHub, accessed on May 9, 2025, &lt;a href=&quot;https://github.com/getsops/sops&quot;&gt;https://github.com/getsops/sops&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A Comprehensive Guide to SOPS: Managing Your Secrets Like A ..., accessed on May 9, 2025, &lt;a href=&quot;https://blog.gitguardian.com/a-comprehensive-guide-to-sops/&quot;&gt;https://blog.gitguardian.com/a-comprehensive-guide-to-sops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Secrets Management in CD Environments with GitOps and SOPS - Platform Engineers, accessed on May 9, 2025, &lt;a href=&quot;https://platformengineers.io/blog/secrets-management-with-gitops-and-sops/&quot;&gt;https://platformengineers.io/blog/secrets-management-with-gitops-and-sops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Manage Kubernetes secrets with SOPS | Flux, accessed on May 9, 2025, &lt;a href=&quot;https://fluxcd.io/flux/guides/mozilla-sops/&quot;&gt;https://fluxcd.io/flux/guides/mozilla-sops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Secrets Manager vs HashiCorp Vault [2025] - Infisical, accessed on May 9, 2025, &lt;a href=&quot;https://infisical.com/blog/aws-secrets-manager-vs-hashicorp-vault&quot;&gt;https://infisical.com/blog/aws-secrets-manager-vs-hashicorp-vault&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Security</category><category>Cloud Computing</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0079-secrets-management-vault-secrets-manager-sops/hero.jpg" length="0" type="image/jpeg"/></item><item><title>The AI Revolution in DevOps: How Smart Tech is Changing Incident Response</title><link>https://mkabumattar.com/blog/post/ai-powered-devops-incident-response-llms/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/ai-powered-devops-incident-response-llms/</guid><description>Explore how AI and Large Language Models (LLMs) are revolutionizing DevOps incident response. Learn about practical applications, benefits, challenges, and future trends. Includes FAQs.</description><pubDate>Sat, 17 May 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Things are getting complicated in the digital world, aren&amp;#39;t they? And with all that complexity, keeping our systems running smoothly is a constant challenge for DevOps teams. When something goes wrong, getting things back on track quickly is super important for keeping customers happy and trust intact. That&amp;#39;s where Artificial Intelligence (AI), especially these cool things called Large Language Models (LLMs), are stepping in. They&amp;#39;re not just making things a little better; they&amp;#39;re totally changing how we deal with problems, promising a future where issues are handled faster and smarter than ever before. Let&amp;#39;s dive into this exciting world of AI in DevOps and see how LLMs are shaking things up when incidents happen.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What&amp;#39;s DevOps Anyway, and Why Does Fixing Problems Fast Matter So Much?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;DevOps is like a big shift in how we build and run software. It&amp;#39;s all about getting rid of the old walls between the people who write the code (developers) and the people who keep it running (operations). The goal? To get applications and services out there super fast, so we can constantly make things better for everyone. Think of it as bringing together people, processes, and the right tools to keep delivering value to customers. The main ideas behind DevOps are things like automating the whole software building process, getting teams to talk and work together better, always trying to improve, and really focusing on what users need. Basically, DevOps wants to make building and releasing good software as smooth and quick as possible. This involves a bunch of steps, from planning to actually running the software, using cool techniques like continuous integration and delivery (CI/CD), keeping track of code changes, and being flexible in how we work.&lt;/p&gt;
&lt;p&gt;Now, when you&amp;#39;re working in this fast-paced DevOps world, being able to fix problems quickly is a huge deal. &amp;quot;Incident response&amp;quot; is just the process that IT and development teams use to handle any major screw-ups that might happen. The big goal here is to stop the problem from causing too much damage, get things back to normal ASAP without spending a ton of time and money, and try to make sure the same thing doesn&amp;#39;t happen again. Speed is key because when systems go down, it can cost a lot more than just money – it can mess with data, hurt your reputation, and make customers lose trust. Having a good plan for dealing with incidents helps DevOps teams keep downtime to a minimum and build a culture of always getting better, making sure systems become more reliable over time. Traditionally, fixing problems involved steps like finding out what happened, trying to fix it, figuring out why it happened, actually fixing it for good, and then looking back to see how we can do better next time. But now, instead of just reacting to problems with local teams and messy processes, modern incident response in DevOps is about being proactive, working together across the globe, and using AI to find and fix problems super fast.&lt;/p&gt;
&lt;p&gt;The whole point of DevOps is to get software out there quickly and efficiently. So, when we can fix problems fast, we&amp;#39;re basically helping to keep that value flowing to customers without interruption. Plus, the way DevOps encourages developers and operations to work together is mirrored in how we now approach fixing problems – it&amp;#39;s all about shared responsibility and using everyone&amp;#39;s knowledge to get things sorted quickly. And just like DevOps loves automation, it makes sense to automate incident response too, cutting down on manual work and the chance of human error when we&amp;#39;re trying to find, fix, and learn from system issues.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Aspect&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Traditional Incident Response&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AI-Powered Incident Response&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Data Analysis&lt;/td&gt;
&lt;td&gt;Looking through logs and alerts by hand&lt;/td&gt;
&lt;td&gt;AI models automatically checking tons of data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incident Triage&lt;/td&gt;
&lt;td&gt;Deciding what&amp;#39;s important based on rules and people&amp;#39;s judgment&lt;/td&gt;
&lt;td&gt;AI systems automatically figuring out what&amp;#39;s what&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response Time&lt;/td&gt;
&lt;td&gt;Slower because people have to do things manually&lt;/td&gt;
&lt;td&gt;Faster, with things happening in real-time thanks to automation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Limited by how many people you have&lt;/td&gt;
&lt;td&gt;Can handle a lot more thanks to AI systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Root Cause Analysis&lt;/td&gt;
&lt;td&gt;Taking a long time to figure out why something happened&lt;/td&gt;
&lt;td&gt;Quickly and automatically finding the cause&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decision Making&lt;/td&gt;
&lt;td&gt;Relying on people&amp;#39;s knowledge and set procedures&lt;/td&gt;
&lt;td&gt;Getting help from AI insights and predictions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Continuous Improvement&lt;/td&gt;
&lt;td&gt;Making things better based on feedback&lt;/td&gt;
&lt;td&gt;AI constantly learning from past problems to improve&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;How Are We Already Seeing AI and Smart Language Models Pop Up in DevOps?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;More and more, we&amp;#39;re seeing AI tools sneak their way into DevOps workflows, and it&amp;#39;s looking like they could really boost how productive we are and make a lot of processes smoother. By using AI, DevOps teams can get rid of those boring, repetitive tasks, make sure their code is top-notch, and get new stuff out the door faster. There are tons of perks to having AI in DevOps, like getting things done quicker, making better software, and deploying it faster. AI is being used for all sorts of things in DevOps, like automatically testing software, keeping a close eye on systems, predicting when things might go wrong, checking code quality, figuring out risks, managing how different parts of a system work together, and making sure we&amp;#39;re using our resources in the best way possible. Plus, AI algorithms are getting good at spotting weird stuff in system logs and performance data, which means we can catch potential problems early and fix them before they cause a real headache.&lt;/p&gt;
&lt;p&gt;Large Language Models (LLMs) are also starting to find their place in DevOps, and they&amp;#39;re promising to change how teams work with code and documentation. LLMs can help write little bits of code, automatically create and update documentation, and even give developers suggestions as they&amp;#39;re typing. Some practical ways LLMs are being used in DevOps include generating basic code or ideas for making it better, automatically updating documentation when code changes, and giving helpful suggestions while coding to cut down on mistakes and make sure everyone&amp;#39;s following the rules. When it comes to getting software ready and out there (Continuous Integration and Deployment, or CI/CD), LLMs are helping by automatically reviewing code to find potential issues early, intelligently creating relevant tests based on code changes, and making documentation easier to keep up to date. Tools like GitHub Copilot and OpenAI Codex are popular for bringing LLMs into existing DevOps workflows. We&amp;#39;re also seeing Natural Language Processing (NLP) being used for something called ChatOps, which lets team members do things like start deployment processes and get system logs just by using simple chat commands. Microsoft has also been busy adding AI to its DevOps tools, with things like GitHub Copilot for Azure, which lets DevOps teams build, fix, and deploy apps on the Azure cloud using plain language. Frameworks like LangChain are designed to make it easier to work with LLMs in DevOps, helping with complex tasks like generating text based on retrieved information and doing multi-step reasoning.&lt;/p&gt;
&lt;p&gt;Right now, the main goal of using AI in DevOps is to help human developers and operators do their jobs better. It&amp;#39;s about taking care of the routine stuff and giving smart insights to help with making decisions, rather than having fully automated systems. LLMs are becoming a big part of this, especially for tasks that involve both code and understanding human language, showing a growing trend towards using these models for lots of different development and operational activities. While using AI and LLMs in DevOps is becoming more common, it&amp;#39;s still pretty early days. Companies are trying out different ways to use them to see where they can get the most benefit, while also being careful about things like security, privacy, and how to manage AI-driven workflows.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How Exactly Can Smart Language Tools Like ChatGPT Change How We Fix Problems in DevOps?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Large Language Models (LLMs) like ChatGPT have some really cool abilities that can totally change how we handle incidents in DevOps, especially by taking over and improving different parts of the incident management process. LLMs can be used for automated IT incident management in several specific ways. They can look at incident reports and automatically sort them into categories based on what the problem is, making sure they get to the right teams to be fixed. Plus, LLMs can help decide which incidents are most important by figuring out how bad they could be and how urgent they are, based on things like which systems are affected, what users are saying, and what happened in the past. This makes sure the really important stuff gets attention right away. For common problems that we&amp;#39;ve seen before, LLMs can be set up to automatically do certain things to fix them, like running scripts or following set procedures. This speeds up the fix and lets IT folks focus on the trickier issues. On top of that, LLMs can create detailed incident reports in real-time, giving a full picture of what happened, what was done to fix it, and what the results were, which is super helpful for looking back and making better decisions in the future. By looking at old incident data, LLMs can also spot trends and give us insights into problems that keep happening, new threats, and how well our systems are doing overall. This helps us take steps to prevent future problems and make our systems more reliable.&lt;/p&gt;
&lt;p&gt;ChatGPT, in particular, is proving to be a really useful tool for DevOps engineers when it comes to dealing with incidents. It can help figure out errors, like when an NGINX server is giving a &amp;quot;502 Bad Gateway&amp;quot; error, by suggesting possible fixes based on the error message and the situation. ChatGPT can also help find the root cause of problems and fix them by looking at logs, giving real-time updates, and offering feedback to DevOps teams while they&amp;#39;re dealing with an incident. What&amp;#39;s more, it can even write scripts to help diagnose problems and automate some of the incident response tasks. By looking at the details of an incident, ChatGPT can give step-by-step instructions on how to fix the underlying issues, which means less downtime and less impact on users. When it&amp;#39;s connected to tools like Azure Sentinel, it can even help with analyzing threats and suggesting ways to fix them. ChatGPT can also automate some of the incident response tasks, like creating tickets, telling the right people what&amp;#39;s going on, and giving status updates throughout the whole incident process.&lt;/p&gt;
&lt;p&gt;Besides general LLMs like ChatGPT, we&amp;#39;re also seeing specialized LLMs pop up that are specifically designed for DevOps incident response. Flip AI, for example, claims to be the first LLM built just for this, offering things like figuring out the root cause, grouping similar alerts, summarizing logs, and even predicting when really bad incidents might happen. Big companies like Meta are also using LLMs to make their incident response processes better, reporting a certain level of accuracy in finding the root causes of problems within their systems. PagerDuty, a leading platform for managing incidents, has also been looking into using LLMs to summarize incident status updates and pull out important information from incident notes and communication channels like Slack to make the whole incident response experience better.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Application Area&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Example Tools/Techniques&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Incident Categorization&lt;/td&gt;
&lt;td&gt;LLMs look at incident reports and automatically sort them based on set criteria, making sure they go to the right place and the right people.&lt;/td&gt;
&lt;td&gt;ChatGPT, Flip AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incident Prioritization&lt;/td&gt;
&lt;td&gt;LLMs figure out how serious and urgent incidents are based on different factors, automatically setting priority levels so the most critical issues get handled first.&lt;/td&gt;
&lt;td&gt;ChatGPT, Flip AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response Actions&lt;/td&gt;
&lt;td&gt;LLMs can automatically take set actions for common incidents, like running scripts or following procedures to fix known problems without needing a human.&lt;/td&gt;
&lt;td&gt;ChatGPT, Flip AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incident Reporting&lt;/td&gt;
&lt;td&gt;LLMs can create detailed reports in real-time, including what the incident was, how it was fixed, and what happened in the end, giving valuable information to everyone involved and for future analysis.&lt;/td&gt;
&lt;td&gt;ChatGPT, Flip AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Root Cause Analysis&lt;/td&gt;
&lt;td&gt;LLMs look at incident data, including logs and system information, to find out why problems happened, often suggesting ways to fix them or areas to look into further.&lt;/td&gt;
&lt;td&gt;ChatGPT, Flip AI, Meta&amp;#39;s LLM-based system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status Updates&lt;/td&gt;
&lt;td&gt;LLMs can summarize what&amp;#39;s happening with an incident and give regular updates to everyone involved, making sure everyone knows how things are progressing.&lt;/td&gt;
&lt;td&gt;ChatGPT, PagerDuty&amp;#39;s LLM exploration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Troubleshooting&lt;/td&gt;
&lt;td&gt;LLMs can help DevOps engineers figure out specific errors or issues by looking at error messages, logs, and settings, often giving step-by-step help or suggesting possible solutions.&lt;/td&gt;
&lt;td&gt;ChatGPT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Script Generation&lt;/td&gt;
&lt;td&gt;LLMs can write scripts in different programming languages for things like diagnosing problems, automating tasks, or implementing fixes, just by asking in plain language what you need.&lt;/td&gt;
&lt;td&gt;ChatGPT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Knowledge Management&lt;/td&gt;
&lt;td&gt;LLMs can automatically handle knowledge management tasks by answering common questions, providing documentation, and suggesting solutions to problems based on what they&amp;#39;ve learned and the context of the question.&lt;/td&gt;
&lt;td&gt;ChatGPT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language Interpretation&lt;/td&gt;
&lt;td&gt;In situations where people speak different languages, LLMs can help translate messages and incident details, making sure everyone can communicate and work together effectively, no matter what language they speak.&lt;/td&gt;
&lt;td&gt;ChatGPT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Can We Use AI-Powered Automation and Robotic Process Automation Together with LLMs to Make Fixing Problems Even Smoother?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;AI-powered automation and Robotic Process Automation (RPA) are two different but helpful ways to make things more efficient and productive in DevOps. RPA is all about using software robots, or bots, to automatically do those repetitive, rule-based tasks, like entering data, working with applications, and setting up systems. AI-powered automation, on the other hand, uses artificial intelligence to let machines learn from data, make smart decisions, and handle more complex tasks that might involve messy data or need flexible responses. RPA has found lots of uses in DevOps, like automating how software is released, making IT operations tasks like setting up servers and applying updates easier, and even helping with the first steps of fixing problems. There are some big benefits to using RPA in DevOps, like getting software out faster, making fewer mistakes, using resources more efficiently, improving security and compliance with automated checks, and being able to easily handle more work when needed.&lt;/p&gt;
&lt;p&gt;Combining AI, including LLMs, and RPA has a lot of potential for making incident response even smoother in DevOps. LLMs can really boost what RPA can do by letting it understand and work with unstructured data, like incident logs and written descriptions, and by allowing for more complex decision-making in automated processes. For example, RPA bots can be used to automatically do the first steps of fixing a problem, like creating tickets and sending out notifications to the right people, while LLMs can help with the next steps of figuring out what&amp;#39;s wrong by looking through incident details and suggesting possible causes. This teamwork is a good example of something called Agentic Process Automation (APA), which is like a mix of RPA&amp;#39;s ability to do things and the smarts of AI agents powered by LLMs, allowing for more independent and flexible ways to handle incidents. LLMs can also be used with RPA to write updates and reports that sound like they were written by a person, triggered by certain events or conditions in an automated RPA process. Plus, RPA can automatically do the fixes that LLMs suggest based on their analysis of the problem.&lt;/p&gt;
&lt;p&gt;RPA gives us the basic tools to automatically do the structured, rule-based tasks in incident response, while AI, especially LLMs, brings the brainpower needed to understand what&amp;#39;s going on with incidents, make smarter decisions, and work with the huge amounts of unstructured data that often come with system failures. This combination allows for a more complete and efficient way to manage incidents, enabling end-to-end automation of processes that used to need a lot of human help. The growing field of Agentic Process Automation shows this trend even more, suggesting a future where AI agents can tell RPA bots what to do to handle different parts of incident response more independently, moving towards systems that can not only react to problems but also proactively work to prevent and fix them with less human involvement. The teamwork between these technologies promises to significantly cut down on manual work, speed up how quickly problems are fixed, and improve how accurate and efficient incident management is in DevOps.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What Are the Big Wins of Using AI and LLMs for Incident Response in DevOps?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Using AI and LLMs for fixing problems in DevOps has some really big advantages that affect different parts of building and running software. One of the biggest is that we can &lt;strong&gt;fix problems faster and get things back to normal quicker (reduced Mean Time to Recovery or MTTR)&lt;/strong&gt;. AI and LLMs can quickly look at tons of data to figure out why an incident happened, suggest the right fixes, and even automatically fix things in some cases, which really cuts down on the time it takes to get services running again. This also leads to &lt;strong&gt;better efficiency and less manual work&lt;/strong&gt; for DevOps teams. By automating a lot of the time-consuming tasks involved in fixing problems, like looking at logs, creating tickets, and doing the first check-up, AI and LLMs free up engineers to work on more important and complex issues.&lt;/p&gt;
&lt;p&gt;Plus, these technologies make it &lt;strong&gt;more accurate to find and categorize incidents&lt;/strong&gt;. AI and LLMs can understand the context of incident reports and system logs better than traditional methods, leading to more accurate sorting and sending of issues to the right teams. Another big win is the ability to &lt;strong&gt;proactively spot and predict potential failures&lt;/strong&gt;. By looking at old data and real-time information, AI and LLMs can see patterns and odd things happening that might point to a problem coming up, letting DevOps teams take steps to prevent it before it even becomes a full-blown incident.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s more, using AI and LLMs can lead to &lt;strong&gt;better teamwork and communication&lt;/strong&gt;. These tools can help everyone understand incidents in the same way, automatically provide updates, and make it easier to share important information, leading to faster and more coordinated responses. AI and LLMs are also great at &lt;strong&gt;automatically figuring out the root cause of problems&lt;/strong&gt;. By sifting through tons of data from different places, they can quickly pinpoint why incidents happened, letting teams put in place targeted solutions and prevent them from happening again. Finally, these technologies help &lt;strong&gt;improve security by finding threats and analyzing weaknesses&lt;/strong&gt;. AI and LLMs can constantly watch systems for unusual activity and potential security breaches, giving early warnings and letting teams take steps to reduce risks. Ultimately, using AI and LLMs in DevOps incident response leads to better understanding and more data-driven decision-making, contributing to a more reliable and resilient software system.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What Should We Watch Out For When Using AI and LLMs for Fixing Problems?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While using AI and LLMs to help fix problems in DevOps has a lot of good points, there are some challenges and things to be aware of. One big worry is about &lt;strong&gt;data privacy and security&lt;/strong&gt; when we train AI models on sensitive information about incidents. Companies need to make sure they have strong ways to hide and protect this information from people who shouldn&amp;#39;t see it. Another issue is &lt;strong&gt;how well these new AI tools work with the tools we already have&lt;/strong&gt; for monitoring, alerts, and managing incidents. It&amp;#39;s really important that the new AI systems can talk to our existing DevOps tools, but getting them to work together smoothly can be tricky.&lt;/p&gt;
&lt;p&gt;We also need to be careful about the &lt;strong&gt;accuracy of LLM outputs&lt;/strong&gt;. Sometimes they can give wrong or misleading information, which could be a big problem if we&amp;#39;re relying on them during a critical incident. Even though LLMs are powerful, they can make mistakes and say things that sound right but aren&amp;#39;t true. There&amp;#39;s also a &lt;strong&gt;risk of AI systems not prioritizing incidents correctly&lt;/strong&gt; if they&amp;#39;re not trained well to understand how serious different events are. Plus, sometimes it&amp;#39;s hard to understand &lt;strong&gt;why an AI model made a certain recommendation&lt;/strong&gt;, which can make DevOps teams less likely to trust and use it. Keeping up with the &lt;strong&gt;constantly changing threats&lt;/strong&gt; means we need to keep training and updating our AI models so they can still find and deal with new kinds of attacks. Also, &lt;strong&gt;biases in AI models&lt;/strong&gt; based on the data they&amp;#39;re trained on could lead to unfair results or missed threats. If we rely too much on AI, we might also &lt;strong&gt;lose some of our own skills&lt;/strong&gt; in analyzing and responding to incidents. Making sure AI systems are &lt;strong&gt;fair and don&amp;#39;t show bias&lt;/strong&gt; in how they handle different types of incidents or users is another important thing to think about.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Challenge&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Mitigation Strategies&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Data Privacy &amp;amp; Security&lt;/td&gt;
&lt;td&gt;Risks of training AI on sensitive incident data.&lt;/td&gt;
&lt;td&gt;Use ways to hide data, keep it safe, and control who can see it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integration Issues&lt;/td&gt;
&lt;td&gt;Problems getting AI to work with existing DevOps tools.&lt;/td&gt;
&lt;td&gt;Choose AI tools that work well with others, use APIs, and maybe use some middleman software.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM Inaccuracies (&amp;quot;Hallucinations&amp;quot;)&lt;/td&gt;
&lt;td&gt;LLMs might give wrong or misleading info.&lt;/td&gt;
&lt;td&gt;Have people double-check, use methods to get info from reliable sources, and train models on specific data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Misprioritization of Incidents&lt;/td&gt;
&lt;td&gt;AI might not correctly judge how serious incidents are.&lt;/td&gt;
&lt;td&gt;Clearly define how serious incidents are, keep training AI models with labeled data, and let people override AI decisions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;quot;Black Box&amp;quot; Nature of AI&lt;/td&gt;
&lt;td&gt;It&amp;#39;s hard to know why AI makes certain decisions.&lt;/td&gt;
&lt;td&gt;Choose AI models that can explain their reasoning or use techniques to understand how they work.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Continuous Training &amp;amp; Updates&lt;/td&gt;
&lt;td&gt;AI models need to be constantly updated to stay effective against new threats.&lt;/td&gt;
&lt;td&gt;Set up processes to regularly retrain models with new data and threat info.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Biases&lt;/td&gt;
&lt;td&gt;If the data used to train AI is biased, it can lead to unfair results.&lt;/td&gt;
&lt;td&gt;Use diverse and representative data for training, check for fairness, and regularly audit AI models for bias.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skill Gaps&lt;/td&gt;
&lt;td&gt;Teams might not have enough people who know AI/ML and DevOps.&lt;/td&gt;
&lt;td&gt;Invest in training, hire people with the right skills, and encourage DevOps and data science teams to work together.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Over-reliance on AI&lt;/td&gt;
&lt;td&gt;People might start to lose their own skills if they trust AI too much.&lt;/td&gt;
&lt;td&gt;Keep a balance between automation and human involvement, encourage continuous learning, and do regular incident response drills.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;What Exciting Things Could Happen in the Future with AI-Powered DevOps Incident Response Using LLMs?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The future of using AI and LLMs to fix problems in DevOps looks really exciting, with lots of new trends and possibilities on the horizon. We can expect to see &lt;strong&gt;more use of predictive analytics&lt;/strong&gt; to spot potential system failures and performance issues early on, letting DevOps teams take action before problems even happen. Another promising trend is the development of &lt;strong&gt;self-healing systems&lt;/strong&gt;, where AI-powered tools will automatically find problems, figure out what&amp;#39;s wrong, and start fixing things without much human help, leading to more reliable systems. We&amp;#39;ll also likely see &lt;strong&gt;more advanced AI-driven monitoring and alerting tools&lt;/strong&gt; that can understand system behavior in more detail, reducing the number of unnecessary alerts and giving us more useful insights. The trend of &lt;strong&gt;integrating AI and LLMs more deeply into existing DevOps platforms and tools&lt;/strong&gt; will probably continue, making these advanced features more accessible and easier to use.&lt;/p&gt;
&lt;p&gt;We might also see the rise of &lt;strong&gt;AI-powered DevOps platforms&lt;/strong&gt; that offer complete solutions for the entire software development process. Expect to see &lt;strong&gt;more use of LLM agents&lt;/strong&gt; for more independent incident response, where AI agents can proactively gather information, figure out problems, and even fix them with minimal human help. Plus, AI and LLMs will likely play a bigger role in &lt;strong&gt;predicting security vulnerabilities and automatically fixing them&lt;/strong&gt;, helping to find and fix security flaws earlier and respond to threats more effectively. There will also be more focus on &lt;strong&gt;explainable AI&lt;/strong&gt; to help us trust and understand the decisions and suggestions made by AI-driven incident response systems. Finally, the integration of AI and LLMs with &lt;strong&gt;edge computing and serverless architectures&lt;/strong&gt; will open up new ways to create distributed and highly scalable incident response solutions.&lt;/p&gt;
&lt;p&gt;The future of AI-powered DevOps incident response is heading towards more automation and independence, with AI agents taking on more responsibility for managing and fixing incidents. This will also mean that security will be more deeply integrated into DevOps, with AI playing a key role in proactively managing threats. However, this future will also require companies to change their mindset to trust AI-driven insights, and we&amp;#39;ll need to develop new skills and roles focused on managing and maintaining these advanced technologies.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions (FAQ)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What&amp;#39;s AIOps, and how does it relate to AI-powered DevOps incident response?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  AIOps, which stands for Artificial Intelligence for IT Operations, is
  basically using AI, including machine learning, to manage IT operations. This
  includes things like dealing with events, managing incidents, keeping an eye
  on performance, and automating tasks. AI-powered DevOps incident response is a
  specific way of using AIOps within the DevOps framework, focusing on how AI
  and LLMs can help us find, fix, and learn from incidents in the software
  development and delivery process more efficiently and effectively.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How can companies start using AI and LLMs for incident response?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Companies can start by looking at their current process for handling incidents
  and figuring out where AI and LLMs could be most helpful. Starting with small
  pilot projects focused on things like automatically sorting incidents or
  analyzing logs can help build understanding and trust. Choosing the right AI
  and LLM tools that work well with their existing DevOps setup and investing in
  training for their teams to use these new technologies effectively are also
  important first steps. Setting clear goals and ways to measure success will
  help track progress and make sure the implementation is helping the business.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some key things to measure to see if AI-powered incident response is working?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Some key things to track include how long it takes to find an incident (Mean
  Time to Detect or MTTD), how long it takes to fix it (Mean Time to Resolve or
  MTTR), how many incidents are automatically found and fixed without human
  help, how much less noise and false alarms we&amp;#39;re getting, how much better our
  systems are staying up and running, and how happy our customers are with how
  quickly and effectively we&amp;#39;re fixing problems.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Will AI and LLMs eventually take the place of DevOps engineers?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  While AI and LLMs can automate a lot of tasks in DevOps, including some parts
  of incident response, it&amp;#39;s unlikely they&amp;#39;ll completely replace DevOps
  engineers. The job of a DevOps engineer involves things like critical
  thinking, solving new problems, planning strategically, and understanding the
  bigger business picture – and those are areas where human expertise is still
  really important. Instead, AI and LLMs will probably help DevOps engineers do
  their jobs better by taking care of the routine stuff and letting them focus
  on more complex and strategic things.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some ethical things to think about when using AI and LLMs for incident response?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Some ethical considerations include making sure data and patient information
  is kept private and secure when training models, being careful about biases in
  AI algorithms that could lead to unfair outcomes, being transparent about how
  AI systems make decisions, and making sure there&amp;#39;s clear responsibility for
  actions taken by AI-powered systems. It&amp;#39;s also important to have a
  &amp;quot;human-in-the-loop&amp;quot; approach for important decisions and to constantly check
  and think about the ethical implications of using these technologies.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;In Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Bringing AI and Large Language Models into DevOps incident response is a game-changer that can really speed up, improve, and make more accurate how we handle system problems. By using the power of AI and LLMs, DevOps teams can fix things faster, do less manual work, see potential problems coming, and work together better. While we need to be careful about things like data privacy, integration, accuracy, and making sure our teams have the right skills, the benefits of using these technologies for a more reliable software system are clear. The future of AI-powered DevOps incident response looks bright, with trends pointing towards more automation, independence, and intelligence in how we keep our increasingly complex digital systems stable and performing well.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What is DevOps? - DevOps Models Explained - Amazon Web Services (AWS), accessed on April 26, 2025, &lt;a href=&quot;https://aws.amazon.com/devops/what-is-devops/&quot;&gt;https://aws.amazon.com/devops/what-is-devops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is DevOps? DevOps Explained | Microsoft Azure, accessed on April 26, 2025, &lt;a href=&quot;https://azure.microsoft.com/en-us/resources/cloud-computing-dictionary/what-is-devops&quot;&gt;https://azure.microsoft.com/en-us/resources/cloud-computing-dictionary/what-is-devops&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Incident Response? - PagerDuty, accessed on April 26, 2025, &lt;a href=&quot;https://www.pagerduty.com/resources/devops/learn/what-is-incident-response/&quot;&gt;https://www.pagerduty.com/resources/devops/learn/what-is-incident-response/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Use AI in DevOps: A Practical Guide - ProjectPro, accessed on April 26, 2025, &lt;a href=&quot;https://www.projectpro.io/article/how-to-use-ai-in-devops/1067&quot;&gt;https://www.projectpro.io/article/how-to-use-ai-in-devops/1067&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft Infuses AI into DevOps Workflows - DevOps.com, accessed on April 26, 2025, &lt;a href=&quot;https://devops.com/microsoft-infuses-ai-into-devops-workflows/&quot;&gt;https://devops.com/microsoft-infuses-ai-into-devops-workflows/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using LLMs for Automated IT Incident Management - OnPage, accessed on April 26, 2025, &lt;a href=&quot;https://www.onpage.com/using-llms-for-automated-it-incident-management/&quot;&gt;https://www.onpage.com/using-llms-for-automated-it-incident-management/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Maximizing Efficiency: Top ChatGPT Prompts for DevOps Engineers ..., accessed on April 26, 2025, &lt;a href=&quot;https://dev.to/s3cloudhub/maximizing-efficiency-top-chatgpt-prompts-for-devops-engineers-56l2&quot;&gt;https://dev.to/s3cloudhub/maximizing-efficiency-top-chatgpt-prompts-for-devops-engineers-56l2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Platform - Flip AI, accessed on April 26, 2025, &lt;a href=&quot;https://www.flip.ai/platform&quot;&gt;https://www.flip.ai/platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How Meta Uses LLMs to Improve Incident Response (and how you ..., accessed on April 26, 2025, &lt;a href=&quot;https://www.tryparity.com/blog/how-meta-uses-llms-to-improve-incident-response&quot;&gt;https://www.tryparity.com/blog/how-meta-uses-llms-to-improve-incident-response&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LLMs and Incident Response? It Starts with Summarization - The ..., accessed on April 26, 2025, &lt;a href=&quot;https://thenewstack.io/llms-and-incident-response-it-starts-with-summarization/&quot;&gt;https://thenewstack.io/llms-and-incident-response-it-starts-with-summarization/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Robotic Process Automation (RPA) and DevOps: A Synergy for ..., accessed on April 26, 2025, &lt;a href=&quot;https://apprecode.com/blog/robotic-process-automation-rpa-and-devops-a-synergy-for-efficiency&quot;&gt;https://apprecode.com/blog/robotic-process-automation-rpa-and-devops-a-synergy-for-efficiency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How RPA and AI Work Together - Benefits &amp;amp; Use Cases - Ciklum, accessed on April 26, 2025, &lt;a href=&quot;https://www.ciklum.com/resources/blog/how-do-rpa-and-ai-work-together-benefits-use-case&quot;&gt;https://www.ciklum.com/resources/blog/how-do-rpa-and-ai-work-together-benefits-use-case&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Agentic Process Automation? A Complete Guide, accessed on April 26, 2025, &lt;a href=&quot;https://www.automationanywhere.com/rpa/agentic-process-automation&quot;&gt;https://www.automationanywhere.com/rpa/agentic-process-automation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unleashing AI in SRE: A New Dawn for Incident Management - DevOps.com, accessed on April 26, 2025, &lt;a href=&quot;https://devops.com/unleashing-ai-in-sre-a-new-dawn-for-incident-management/&quot;&gt;https://devops.com/unleashing-ai-in-sre-a-new-dawn-for-incident-management/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Artificial Intelligence</category><category>Incident Management</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0078-ai-powered-devops-incident-response-llms/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Platform Engineering: Building Internal Developer Platforms (IDPs)</title><link>https://mkabumattar.com/blog/post/platform-engineering-building-internal-developer-platforms/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/platform-engineering-building-internal-developer-platforms/</guid><description>Learn how platform engineering and Internal Developer Platforms (IDPs) are revolutionizing software development. Discover benefits, challenges, best practices, and the Spotify case study. Simplify complexity and boost developer productivity!</description><pubDate>Sat, 10 May 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ever feel like developers spend more time wrestling with infrastructure than actually writing code? In today&amp;#39;s fast-moving world of software, that&amp;#39;s a real problem. So, how do we help our teams focus on creating awesome stuff without getting lost in the weeds of servers and setups? The answer is something called &lt;strong&gt;platform engineering&lt;/strong&gt;, and it&amp;#39;s all about building &lt;strong&gt;internal developer platforms (IDPs)&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What&amp;#39;s the Deal with Platform Engineering and Why Should You Care About These IDPs?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Think of &lt;strong&gt;platform engineering&lt;/strong&gt; as the grown-up version of DevOps. It takes those good ideas and focuses them on making developers&amp;#39; lives better. It&amp;#39;s about creating a smooth, safe, and easy way for development teams to do their thing – build great software. This means giving them the tools and processes they need to work independently, all within a secure and well-managed environment. It&amp;#39;s like treating developers as your main customers and building a product just for them. Experts are saying that platform engineering is the way of the future, with more and more companies realizing they need dedicated teams to make this happen. It&amp;#39;s not just about the tech; it&amp;#39;s about a whole new way of thinking that puts the developer experience first to get better results for the business. Companies are learning that just automating things isn&amp;#39;t enough. You need to really focus on what developers need through these internal platforms to grow effectively.&lt;/p&gt;
&lt;p&gt;Now, what does all this platform engineering actually &lt;em&gt;look&lt;/em&gt; like? Often, it takes the shape of an &lt;strong&gt;internal developer platform (IDP)&lt;/strong&gt;. Imagine an IDP as a self-service shop for developers. They can go there and get all the &lt;strong&gt;infrastructure&lt;/strong&gt;, tools, and processes they need to build, deploy, and manage their applications. These platforms are like internal products, carefully designed with all the right tools and information so software teams can deliver their work quickly and on their own. A big goal of an IDP is to take away the headache of complicated tech stuff, so developers can focus on what they&amp;#39;re good at. By having this central hub of knowledge and tools, IDPs cut down on the need for manual work. Each IDP is unique, built to fit the specific needs of a company, bringing together different tools and workflows into one easy-to-use system. The idea of &amp;quot;paved paths&amp;quot; in an IDP is like creating well-trodden trails that become safe and efficient roads over time. It&amp;#39;s about guiding developers towards best practices without slowing them down.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What&amp;#39;s So Great About Having an Internal Developer Platform for Your Teams?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Setting up internal developer platforms brings a ton of real advantages to software development teams. One of the biggest wins is a huge jump in how much developers can get done, while also making their jobs less stressful. IDPs do this by taking over many of the boring infrastructure tasks, like setting up new servers and services. This frees up developers to spend their time on more important and creative work. Plus, having everything in one place, like a service catalog with all the tools and processes, makes things much easier for developers. Studies show that when companies focus on making developers happy, they actually get more work done. The self-service part of IDPs also means developers can be more independent, getting what they need without having to wait on other teams. It&amp;#39;s all about making developers&amp;#39; work lives better so they can deliver better results for the company.&lt;/p&gt;
&lt;p&gt;Beyond just individual developers, IDPs also make the whole operation run more smoothly. These platforms bring together all the important infrastructure pieces, like the systems that build and deploy code (CI/CD), monitoring tools, security measures, and cloud resources, into one organized platform. When developers can get what they need themselves through the IDP, it means less back-and-forth with operations teams, leading to better teamwork. This improved communication and coordination across teams ultimately makes everyone more effective.&lt;/p&gt;
&lt;p&gt;IDPs also help companies grow their development efforts with more confidence and fewer mistakes. By making sure that the environments where code is built and run are the same, and by automating the deployment process, IDPs help get rid of the inconsistencies that often cause errors. Automation also takes away the chance of manual deployment mistakes and makes it easier to handle more work when needed. Data shows that companies using an IDP have fewer problems when they make changes, and those using platform engineering see their systems become more reliable.&lt;/p&gt;
&lt;p&gt;Because IDPs automate and streamline processes, teams can release new features and updates much faster. With IDPs, teams can deploy applications more often, sometimes even multiple times a day, which is a big improvement for companies without these platforms. This speed comes from automated pipelines and consistent environments throughout the development process, eliminating slowdowns. As a result, companies can react quicker to what the market wants and deliver new things faster.&lt;/p&gt;
&lt;p&gt;Security and compliance also get a boost from IDPs. The automation built into an IDP makes platforms more secure and less likely to have weaknesses. Features like controlling who can access what and automatically enforcing rules ensure that security measures are consistently applied, reducing human errors and unauthorized access. By automatically checking for compliance, IDPs help companies meet industry standards and regulations.&lt;/p&gt;
&lt;p&gt;On top of all this, IDPs offer even more advantages. Dashboards within IDPs can show important information from software catalogs and scorecards, helping with planning and spotting potential problems. New developers can get up to speed faster because they can quickly learn about the tech and access the tools they need without waiting around. If something goes wrong, IDPs can help fix it faster by providing a central place for all the relevant information and tools. Engineering teams can also work faster because they have all their tools and data in one spot, reducing the need to switch between different things. Plus, IDPs can help keep costs down by showing where money is being spent and allowing for the setting of budget limits. They also help everyone in the company stay on the same page ensure better compliance and give development teams more freedom. The environments where code is built become more consistent and teams can collaborate and share knowledge better. Strong CI/CD integrations are usually included and a comprehensive catalog of services encourages reusing existing components. Finally, IDPs make it easier for developers to get the resources they need. With all these benefits, from making developers more productive to improving efficiency, security, and cost management, it&amp;#39;s clear that IDPs can really transform software development.&lt;/p&gt;
&lt;p&gt;To make these advantages even clearer, here&amp;#39;s a quick rundown of the key benefits of using IDPs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Benefit Category&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Specific Benefit&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Supporting Snippet(s)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Productivity&lt;/td&gt;
&lt;td&gt;Boosting Developer Productivity&lt;/td&gt;
&lt;td&gt;&amp;quot;IDPs do this by automating routine infrastructure tasks, which takes a load off developers.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Productivity&lt;/td&gt;
&lt;td&gt;Reducing Developer Burden&lt;/td&gt;
&lt;td&gt;&amp;quot;This frees up developers to spend their time on more important and creative work.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Efficiency&lt;/td&gt;
&lt;td&gt;Elevating Operational Efficiency&lt;/td&gt;
&lt;td&gt;&amp;quot;IDPs also help companies grow their development efforts with more confidence and fewer mistakes.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Efficiency&lt;/td&gt;
&lt;td&gt;Streamlining and Standardizing Operations&lt;/td&gt;
&lt;td&gt;&amp;quot;These platforms bring together all the important infrastructure pieces, like the systems that build and deploy code (CI/CD), monitoring tools, security measures, and cloud resources, into one organized platform.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability &amp;amp; Reliability&lt;/td&gt;
&lt;td&gt;Scaling with Confidence&lt;/td&gt;
&lt;td&gt;&amp;quot;IDPs also help companies grow their development efforts with more confidence and fewer mistakes.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability &amp;amp; Reliability&lt;/td&gt;
&lt;td&gt;Reducing Errors&lt;/td&gt;
&lt;td&gt;&amp;quot;By making sure that the environments where code is built and run are the same, and by automating the deployment process, IDPs help get rid of the inconsistencies that often cause errors.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Increased Deployment Frequency&lt;/td&gt;
&lt;td&gt;&amp;quot;With IDPs, teams can deploy applications more often, sometimes even multiple times a day, which is a big improvement for companies without these platforms.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Faster Time to Market&lt;/td&gt;
&lt;td&gt;&amp;quot;This speed comes from automated pipelines and consistent environments throughout the development process, eliminating slowdowns.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security &amp;amp; Compliance&lt;/td&gt;
&lt;td&gt;Increased Security&lt;/td&gt;
&lt;td&gt;&amp;quot;The automation built into an IDP makes platforms more secure and less likely to have weaknesses.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security &amp;amp; Compliance&lt;/td&gt;
&lt;td&gt;Improved Compliance&lt;/td&gt;
&lt;td&gt;&amp;quot;By automatically checking for compliance, IDPs help companies meet industry standards and regulations.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Planning &amp;amp; Bottleneck Identification&lt;/td&gt;
&lt;td&gt;Effective Planning&lt;/td&gt;
&lt;td&gt;&amp;quot;Dashboards within IDPs can show important information from software catalogs and scorecards, helping with planning and spotting potential problems.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Planning &amp;amp; Bottleneck Identification&lt;/td&gt;
&lt;td&gt;Bottleneck Identification&lt;/td&gt;
&lt;td&gt;&amp;quot;Dashboards within IDPs can show important information from software catalogs and scorecards, helping with planning and spotting potential problems.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Onboarding&lt;/td&gt;
&lt;td&gt;Speeding up Developer Onboarding&lt;/td&gt;
&lt;td&gt;&amp;quot;New developers can get up to speed faster because they can quickly learn about the tech and access the tools they need without waiting around.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incident Management&lt;/td&gt;
&lt;td&gt;Lower MTTR&lt;/td&gt;
&lt;td&gt;&amp;quot;If something goes wrong, IDPs can help fix it faster by providing a central place for all the relevant information and tools.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Engineering Velocity&lt;/td&gt;
&lt;td&gt;Higher Engineering Velocity&lt;/td&gt;
&lt;td&gt;&amp;quot;Engineering teams can also work faster because they have all their tools and data in one spot, reducing the need to switch between different things.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost Management&lt;/td&gt;
&lt;td&gt;Reduced and Controlled Costs&lt;/td&gt;
&lt;td&gt;&amp;quot;IDPs can help keep costs down by showing where money is being spent and allowing for the setting of budget limits.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Governance&lt;/td&gt;
&lt;td&gt;Improved Alignment&lt;/td&gt;
&lt;td&gt;&amp;quot;IDPs also help companies grow their development efforts with more confidence and fewer mistakes.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Governance&lt;/td&gt;
&lt;td&gt;Enhanced Compliance&lt;/td&gt;
&lt;td&gt;&amp;quot;By automatically checking for compliance, IDPs help companies meet industry standards and regulations.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Governance&lt;/td&gt;
&lt;td&gt;Stronger Governance&lt;/td&gt;
&lt;td&gt;&amp;quot;The automation built into an IDP makes platforms more secure and less likely to have weaknesses.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autonomy&lt;/td&gt;
&lt;td&gt;Increased Autonomy for Teams&lt;/td&gt;
&lt;td&gt;&amp;quot;The self-service part of IDPs also means developers can be more independent, getting what they need without having to wait on other teams.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Environment Consistency&lt;/td&gt;
&lt;td&gt;Enhanced Consistency Across Environments&lt;/td&gt;
&lt;td&gt;&amp;quot;By making sure that the environments where code is built and run are the same, and by automating the deployment process, IDPs help get rid of the inconsistencies that often cause errors.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collaboration&lt;/td&gt;
&lt;td&gt;Improved Collaboration&lt;/td&gt;
&lt;td&gt;&amp;quot;IDPs also help companies grow their development efforts with more confidence and fewer mistakes.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Knowledge Sharing&lt;/td&gt;
&lt;td&gt;Enhanced Knowledge Sharing&lt;/td&gt;
&lt;td&gt;&amp;quot;Features that allow developers to share insights, document solutions, and contribute to a shared knowledge base can be very helpful.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD&lt;/td&gt;
&lt;td&gt;Robust CI/CD Integrations&lt;/td&gt;
&lt;td&gt;&amp;quot;Strong CI/CD integrations are usually included.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reusability&lt;/td&gt;
&lt;td&gt;Comprehensive Service Catalog&lt;/td&gt;
&lt;td&gt;&amp;quot;A comprehensive catalog of services encourages reusing existing components.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource Access&lt;/td&gt;
&lt;td&gt;Streamlined Access to Resources&lt;/td&gt;
&lt;td&gt;&amp;quot;IDPs make it easier for developers to get the resources they need.&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Building an IDP Sounds Awesome, But What are the Gotchas?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While the idea of internal developer platforms is exciting, getting there isn&amp;#39;t always a walk in the park. Even though they&amp;#39;re meant to simplify things, building and keeping an IDP running can get pretty complex. Setting up, connecting, and managing all the different infrastructure pieces like Kubernetes, service meshes, and CI/CD pipelines takes a lot of skill and can quickly become overwhelming. Sometimes, instead of making software releases faster, a platform that&amp;#39;s too complicated can actually slow things down because engineers end up spending more time fixing infrastructure problems. This means you need to be really thoughtful and take things one step at a time when you&amp;#39;re building an IDP.&lt;/p&gt;
&lt;p&gt;Another thing to watch out for is technical debt building up in your IDP over time. This can happen when you use old software, take shortcuts to meet deadlines, or don&amp;#39;t write enough documentation. These things can make the platform less stable, more vulnerable to security issues, and more expensive to maintain. Spending time to fix this technical debt can take away valuable resources from working on your main products.&lt;/p&gt;
&lt;p&gt;Building a good IDP also takes a lot of time and effort from your engineering teams. This can pull their focus away from actually developing your products. The time spent initially building the platform and then keeping it running might, in some cases, outweigh the benefits of faster releases and better efficiency. Some people estimate that building a fully functional IDP can take a long time, maybe even years, and require a dedicated team.&lt;/p&gt;
&lt;p&gt;One common mistake when building IDPs is focusing too much on the continuous integration/continuous deployment (CI/CD) and runtime parts, and not enough on things like software design and the overall experience for developers. This can lead to a platform that automates deployments but doesn&amp;#39;t really make the daily work of developers any easier or more enjoyable.&lt;/p&gt;
&lt;p&gt;Choosing the right tools and technologies for an IDP is another tricky part. The world of cloud-native tech is huge and always changing, so platform engineers have to spend a lot of time checking out different tools and getting good at using them. Also, companies need to be careful not to get locked into using only one vendor&amp;#39;s products and should try to find solutions that work across different cloud providers to stay flexible.&lt;/p&gt;
&lt;p&gt;Finding platform engineers with the right skills can also be a big challenge. Building and maintaining an IDP requires special knowledge in areas like automating infrastructure, building APIs, security best practices, and connecting different systems. People with this mix of skills can be hard to find and expensive to hire.&lt;/p&gt;
&lt;p&gt;For companies with limited resources, trying to build an IDP might accidentally take focus away from their main business goals. In these cases, if the platform development fails or doesn&amp;#39;t give the expected return, it could put the whole business at risk.&lt;/p&gt;
&lt;p&gt;A really important part of building a successful IDP is thinking of it as a product and getting the developers who will use it involved as much as possible. A common mistake is when platform teams think they know best and don&amp;#39;t really listen to what developers need. It&amp;#39;s crucial to actively listen to developers, understand their biggest frustrations, and build the platform to solve those specific problems, rather than just imposing a solution based on what the platform team thinks is best.&lt;/p&gt;
&lt;p&gt;Finally, it&amp;#39;s important to realize that investing in an IDP might not be the right move for every company. There are situations where other approaches might make more sense, like if you have a small development team, your development isn&amp;#39;t very complex, your company isn&amp;#39;t ready for standardized processes, your development speed is already slow, you have a tight budget, developers aren&amp;#39;t really complaining about any major issues, your engineering goals don&amp;#39;t align with business goals, your current tools are hard to integrate, you need results quickly, or you&amp;#39;re not prepared for the ongoing maintenance that an IDP requires. A key reason why IDP projects fail is often a lack of good communication between the team building the platform and the developers who are supposed to use it. Also, if it&amp;#39;s not clear what&amp;#39;s really important and what should be included in the platform, it can lead to wasted effort and a platform that doesn&amp;#39;t actually meet the needs of its users. The many potential challenges and reasons why an IDP might not be the right fit show just how complex this undertaking can be and highlight the importance of careful planning, understanding your company&amp;#39;s specific situation, and really focusing on the needs of your developers.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Can You Show Me a Success Story? How Does Spotify Use Platform Engineering and IDPs?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When we talk about companies that have successfully used platform engineering and internal developer platforms, Spotify&amp;#39;s journey with Backstage is a prime example. Backstage is an open-source internal developer portal that has become a key part of Spotify&amp;#39;s platform engineering strategy. Spotify built Backstage internally to make it easier for new developers to join the team and to improve the overall developer experience by giving engineers self-service tools and clear paths to get their code into production, often called &amp;quot;paved roads&amp;quot; or &amp;quot;golden paths&amp;quot;. Initially, the main goal was to create a comprehensive catalog of all their software and services to make it clear who owned what and to encourage reusing existing components. Before Backstage, developers at Spotify reportedly spent a lot of time just trying to find the information they needed to do their jobs effectively.&lt;/p&gt;
&lt;p&gt;Recognizing that their internal solution could be valuable to others, Spotify made Backstage open-source in March 2020 and later donated it to the Cloud Native Computing Foundation (CNCF). Since then, it has become very popular and is now one of the go-to solutions for companies starting their own platform engineering initiatives. Within Spotify, their internal version of Backstage acts like a central hub for their entire infrastructure, used daily by over 1600 engineers to manage a huge system of more than 14,000 software components.&lt;/p&gt;
&lt;p&gt;The way Backstage is built, with a system of plugins, makes it very flexible and adaptable to different needs. Some of the main plugins include the Software Catalog, which keeps track of all the important information about software components; Templates, which allow platform teams to create pre-defined blueprints for new services; TechDocs, a built-in tool for automatic documentation; Search, which lets you customize how you search through the catalog and documentation; and a Kubernetes plugin, which helps service owners monitor the health of their Kubernetes services. The basic structure of Backstage includes three main parts: the main Backstage user interface, the UI plugins along with the services that support them, and databases to store necessary information. This design keeps the core Backstage functionality separate from the specific setup used by a company and the various plugins that add custom features.&lt;/p&gt;
&lt;p&gt;Using Backstage has brought significant benefits to Spotify. It has made it easier for new developers to get started and has greatly reduced the time developers spend searching for information. Spotify reported that an impressive 99% of their engineering team voluntarily adopted Backstage, showing that developers find it really useful. Also, data suggests that teams at Spotify that use Backstage a lot have seen more activity on GitHub and an overall increase in how much they get done. The platform also helps standardize the technologies used across the company and ensures that quality standards are met through the use of the Scaffolder plugin. It also integrates with other important tools, like Soundcheck for checking the health of components and a Vulnerabilities plugin for finding security issues. For managing incidents, Backstage connects with PagerDuty, giving developers quick access to on-call information and details about incidents. Moreover, Backstage encourages the idea of platformization and the reuse of code and components within the company.&lt;/p&gt;
&lt;p&gt;Despite its success, the complexity of installing and setting up Backstage has led to the creation of several commercial alternatives in recent years. These include platforms like Cortex, Humanitec Portal, Getport.io, Configure 8, OpsLevel, Rely, and Compass by Atlassian. Companies considering Backstage should also be aware of the potentially high costs and the significant time investment needed for extensive customization and ongoing maintenance, especially for large companies. Spotify&amp;#39;s experience highlights the importance of thinking of your platform as a product for any successful IDP implementation, making sure that the platform is constantly improved based on developer feedback and treated as a valuable internal product. The Spotify example shows how a well-implemented internal developer platform can transform the developer experience and boost productivity at scale. However, it also shows the effort and resources required, suggesting that while building your own with Backstage can be very effective, managed IDP solutions might be an easier path for some organizations.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Got Questions? Let&amp;#39;s Dive into Some Common Ones About Platform Engineering and IDPs.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Many people and companies looking into platform engineering and internal developer platforms often have similar questions. Understanding these frequently asked questions can help clarify these ideas.&lt;/p&gt;
&lt;Accordion client:load title=&quot;What makes an IDP a &apos;platform&apos;?&quot;&gt;
  An internal developer platform is called a &quot;platform&quot; because it raises the
  level of **abstraction** for its users, giving them a more
  Platform-as-a-Service (PaaS)-like experience compared to directly dealing with
  Infrastructure-as-a-Service (IaaS) resources. It acts as a bridge between the
  teams managing the underlying platform and the development teams that use its
  services. Ultimately, a platform helps deliver value from start to finish,
  allowing applications to provide features to end-users, no matter what
  specific infrastructure is involved. While a developer portal can be a
  user-friendly way to interact with an IDP, it&apos;s not essential for something to
  be considered a platform; using APIs or command-line tools can also count. A
  key feature of an IDP is that it&apos;s custom-built to fit a company&apos;s unique
  needs, processes, and rules.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the core principles of platform engineering?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Microsoft&amp;#39;s Platform Engineering Capabilities Model outlines six key areas:
  investment, adoption, governance, provisioning and management, interfaces, and
  measurements and feedback. These principles help guide companies in setting up
  and growing their platform engineering efforts.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the key features of an internal developer platform?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  These often include a central catalog of software components with a
  self-service interface, giving developers one place to access all the tools
  and information they need. Software health scorecards provide a live view of
  how well applications are performing. Integrations and the ability to extend
  the platform are crucial, allowing the IDP to connect with existing tools and
  be customized for specific company needs. Finally, software templates, often
  called &amp;quot;golden paths,&amp;quot; let developers quickly create new projects and services
  based on pre-set best practices.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do internal developer platforms boost developer productivity?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  IDPs do this by automating routine infrastructure tasks, which takes a load
  off developers. They also make things less complicated by providing a single
  place to find everything, simplifying the development process. By making the
  overall experience better for developers and giving them self-service options,
  IDPs allow them to focus on coding and delivering value.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the common pitfalls in building an internal developer platform?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  These include the difficulty of building and managing such platforms, the risk
  of technical debt building up over time, the significant time and resources
  required, potential problems with connecting to external tools, security risks
  with DIY platforms, challenges in setting up good governance, overlooking what
  happens after deployment, the need for constant updates, and the difficulty of
  finding and keeping skilled people.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does Spotify measure the success of their internal developer platform?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  While the exact metrics might vary, Spotify&amp;#39;s reported high voluntary adoption
  rate (99%) of Backstage is a strong sign that it&amp;#39;s seen as valuable and
  successful within their engineering team.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does platform engineering abstract infrastructure complexity?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Platform engineering does this by creating an IDP that acts as a simple way
  for developers to access pre-configured and standardized infrastructure
  components and services through self-service tools. This hides the underlying
  complexities of the infrastructure from developers, allowing them to focus on
  their main tasks.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the best practices for designing an internal developer platform?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  These include prioritizing the developer experience, ensuring smooth
  integration across all tools, making it easy to find things and providing good
  documentation, encouraging collaboration and knowledge sharing, focusing on
  automation and strong governance, thinking of the platform as a product,
  focusing on the needs of developer &amp;quot;customers,&amp;quot; providing self-service
  options, making the platform optional at first, starting with a clear plan,
  getting regular feedback from users, testing with a small team first, having a
  central platform team, and designing the platform to be flexible.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the expected future trends in platform engineering?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  These include more companies adopting platform engineering, the increasing use
  of artificial intelligence and machine learning to automate tasks, further
  improvements in IDP capabilities, the growing trend of managing
  infrastructure, data, and applications as code, the rise of platforms built
  from reusable components, a greater focus on using data to improve platforms,
  the impact of AI on development workflows, a continued focus on security and
  compliance, the adoption of environmentally friendly software practices, and
  the spread of platform engineering beyond just big tech companies.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How Do Infrastructure and Abstraction Form the Core of Platform Engineering and IDPs?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Infrastructure&lt;/strong&gt; and &lt;strong&gt;abstraction&lt;/strong&gt; are the fundamental building blocks of platform engineering and internal developer platforms. IDPs are all about giving developers easy, self-service access to the underlying infrastructure they need to build, deploy, and run their applications. This includes everything from where their applications are hosted and the computing power they use, to the essential tools that support them. The key is that the IDP presents this infrastructure in a way that hides many of the technical details behind an easy-to-use developer portal and clear APIs. Essentially, an IDP often layers several logical platforms on top of each other, bringing together different technology functions, platforms, and tools into a single, unified experience for developers. Instead of developers having to go through complicated IT service requests or build entire cloud environments from scratch, an IDP gives them exactly what they need in an automated, fast, and organized way that fits their workflows. Platform engineering, as a practice, involves not just managing this underlying infrastructure but also creating the tools and processes that guide developers through a smooth workflow, often called a &amp;quot;Golden Path,&amp;quot; tailored to their specific needs. Furthermore, IDPs play a crucial role in making cloud infrastructure more efficient by automating development and deployment processes, making better use of resources, improving performance, and saving costs through seamless integration with various cloud services. The success of any platform engineering effort and the IDP it creates depends heavily on the close collaboration of infrastructure platform engineers who ensure a unified and efficient experience for developers, whether they&amp;#39;re using resources from a cloud provider or an internal infrastructure team. So, infrastructure provides the essential components and capabilities that are then made accessible to developers through the IDP, all orchestrated by the principles of platform engineering.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Abstraction&lt;/strong&gt; is the main way that platform engineering and IDPs deliver their core value. Platform engineering aims to make things simpler for developers and speed up development by creating an &lt;strong&gt;abstraction layer&lt;/strong&gt; – the IDP – that sits between developers and the complexities of the underlying technology. This &lt;strong&gt;abstraction&lt;/strong&gt; hides the intricate details of infrastructure management from developers, allowing them to focus on writing code and building features. IDPs provide a consistent and standardized way to interact with infrastructure, which not only makes it easier to use but also makes it more portable across different environments. By abstracting away the underlying complexities, platform engineering helps standardize workflows, automate repetitive tasks, and embed best practices within the platform. Finding the right level of &lt;strong&gt;abstraction&lt;/strong&gt; is crucial; it should be enough to provide security and compliance by default while not being so complicated that it&amp;#39;s hard to use. The benefits of this &lt;strong&gt;abstraction&lt;/strong&gt; are many, including improved developer productivity, faster time to market for applications, better system reliability and scalability, optimized use of resources, and stronger security. Essentially, &lt;strong&gt;abstraction&lt;/strong&gt; is a powerful tool that helps developers be more efficient and effective by hiding the underlying technical complexities, ultimately leading to faster software delivery and better business results. However, it&amp;#39;s important to find the right balance to avoid making things too simple or adding new layers of complexity that could undo the intended benefits.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Ready to Build Your Own IDP? What are the Essential Best Practices and Considerations?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;For companies looking to build their own internal developer platforms, there are several best practices and key things to think about that can greatly increase their chances of success. First and foremost, it&amp;#39;s crucial to &lt;strong&gt;think like a product team&lt;/strong&gt;. This means treating the IDP as an internal product with clear features, a plan for the future, and a focus on the needs of its main users – the developers. Success should be measured by how well the platform meets their needs and helps them achieve better results.&lt;/p&gt;
&lt;p&gt;A core idea in platform engineering is to &lt;strong&gt;focus on the developer experience (DX)&lt;/strong&gt;. The IDP should be easy to use, fast, and simple to navigate. Getting feedback from developers is essential to understand their problems and make continuous improvements to the platform.&lt;/p&gt;
&lt;p&gt;Making sure there&amp;#39;s &lt;strong&gt;integration across all your tools&lt;/strong&gt; is another critical best practice. The IDP should work smoothly with the various DevOps tools and platforms that developers already use, such as CI/CD pipelines, version control systems, and cloud services, ideally through APIs and a consistent user interface.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s vital to make it easy for developers to find what they need. So, the IDP should &lt;strong&gt;enable discoverability and provide good documentation&lt;/strong&gt;. Implementing metadata, tagging systems, and strong search features, along with comprehensive and up-to-date documentation, are key to making this happen.&lt;/p&gt;
&lt;p&gt;An IDP can also be a great place to &lt;strong&gt;encourage collaboration and knowledge sharing&lt;/strong&gt; among development teams. Features that allow developers to share insights, document solutions, and contribute to a shared knowledge base can be very helpful.&lt;/p&gt;
&lt;p&gt;To improve efficiency and maintain standards, companies should &lt;strong&gt;focus on automation and governance&lt;/strong&gt; within their IDPs. Automating repetitive tasks and building in security, compliance, and best practices into the platform are essential.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s often a good idea to &lt;strong&gt;start small and build gradually&lt;/strong&gt; when creating an IDP. Begin with a basic platform that solves the most pressing problems and then slowly add more features based on user feedback and changing needs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Getting key people involved early&lt;/strong&gt; in the process is crucial for getting different viewpoints and making sure everyone is on the same page. This includes developers, operations teams, and managers.&lt;/p&gt;
&lt;p&gt;A platform that has lots of features but is hard to use probably won&amp;#39;t be very effective. Therefore, &lt;strong&gt;prioritizing user experience&lt;/strong&gt; through testing and making changes based on user feedback is very important.&lt;/p&gt;
&lt;p&gt;Clearly &lt;strong&gt;defining who is responsible for what&lt;/strong&gt; between the platform team and the development teams using the IDP is essential to avoid confusion and ensure accountability. Setting up &amp;quot;golden paths&amp;quot; – clear and approved ways to deploy code that include all necessary requirements – can also greatly improve consistency and reduce errors.&lt;/p&gt;
&lt;p&gt;Implementing &lt;strong&gt;strong monitoring and observability&lt;/strong&gt; within the IDP gives developers the insights they need to understand how their applications and the underlying infrastructure are performing.&lt;/p&gt;
&lt;p&gt;Given that technology is always changing, it&amp;#39;s important to &lt;strong&gt;plan for flexibility&lt;/strong&gt; in the design of the IDP so it can adapt to new needs and incorporate new technologies.&lt;/p&gt;
&lt;p&gt;Finally, companies should carefully &lt;strong&gt;consider whether to build or buy&lt;/strong&gt; an IDP. Depending on their resources, time constraints, and specific needs, a commercial IDP solution might be a better fit than building one from scratch. These best practices and considerations provide a strong foundation for companies looking to build effective internal developer platforms that empower their development teams and drive innovation.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What Does the Future Hold for Platform Engineering and Internal Developer Platforms?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The world of platform engineering and internal developer platforms is set to change a lot in the coming years. We can expect to see &lt;strong&gt;more and more companies&lt;/strong&gt; adopting platform engineering principles and IDPs, as they realize how valuable they are for making software development and operations smoother.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Artificial intelligence (AI) and machine learning (ML)&lt;/strong&gt; are likely to become more and more integrated into platform engineering workflows and IDPs. These technologies will probably automate tasks like managing infrastructure, spotting problems, and improving performance, making platforms more efficient and smart.&lt;/li&gt;
&lt;li&gt;IDPs themselves will keep getting better, becoming more advanced, easier to use, and simpler to maintain. We can expect to see them connect more deeply with various tools and services, as well as use AI to give recommendations and better support different technologies and environments.&lt;/li&gt;
&lt;li&gt;The trend of treating &lt;strong&gt;infrastructure, data, and applications as code&lt;/strong&gt; is going to become even more common. By managing everything through configuration files, companies can achieve greater automation, consistency, and scalability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composability&lt;/strong&gt; is becoming a key idea in platform engineering. The focus will be on building platform components that are modular and reusable, so they can be easily put together into custom workflows to meet the specific needs of development teams.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using data to improve platforms&lt;/strong&gt; will become more important, with teams increasingly using metrics and observability data to understand how their platforms are being used, identify bottlenecks, and personalize the experience for developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generative AI&lt;/strong&gt; is expected to play a big role by automating tasks like writing basic code, creating CI/CD pipelines, and even improving platform documentation.&lt;/li&gt;
&lt;li&gt;The focus on &lt;strong&gt;security and compliance&lt;/strong&gt; will remain a top priority, with security practices being integrated throughout the entire software development process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environmentally friendly software practices&lt;/strong&gt; are expected to gain traction as companies become more aware of their impact on the planet. Platform engineering will help optimize resource use and promote energy-efficient development.&lt;/li&gt;
&lt;li&gt;Finally, &lt;strong&gt;platform engineering will likely become more accessible&lt;/strong&gt; to a wider range of companies, not just the big tech giants, but also mid-sized businesses and startups. These future trends suggest that platform engineering and IDPs will continue to evolve, driven by new technologies and a growing understanding of how important the developer experience is for business success.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion: Making Developers Happy with Platform Engineering.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In short, platform engineering and internal developer platforms are a big step forward in how companies handle software development. By focusing on creating easy-to-use, self-service environments for developers, IDPs offer many benefits, including increased productivity, better efficiency, improved scalability, and stronger security. While building and maintaining an IDP has its challenges, the potential rewards in terms of happy developers and faster software releases are significant. As seen with successful examples like Spotify&amp;#39;s Backstage, a well-designed IDP can be a game-changer for engineering teams. By embracing the principles of platform engineering and putting the developer experience first, companies can empower their teams to innovate faster, deliver higher-quality software, and ultimately achieve their business goals more effectively.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The following references were used to compile this article. They provide additional insights and information on platform engineering, internal developer platforms, and best practices for implementation.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What is platform engineering? | Microsoft Learn, accessed on April 11, 2025, &lt;a href=&quot;https://learn.microsoft.com/en-us/platform-engineering/what-is-platform-engineering&quot;&gt;https://learn.microsoft.com/en-us/platform-engineering/what-is-platform-engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Platform Engineering? | Atlassian, accessed on April 11, 2025, &lt;a href=&quot;https://www.atlassian.com/developer-experience/platform-engineering&quot;&gt;https://www.atlassian.com/developer-experience/platform-engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Internal Developer Platform [Benefits + Best Practices] | Atlassian, accessed on April 11, 2025, &lt;a href=&quot;https://www.atlassian.com/developer-experience/internal-developer-platform&quot;&gt;https://www.atlassian.com/developer-experience/internal-developer-platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is an Internal Developer Platform (IDP)? - Spacelift, accessed on April 11, 2025, &lt;a href=&quot;https://spacelift.io/blog/what-is-an-internal-developer-platform&quot;&gt;https://spacelift.io/blog/what-is-an-internal-developer-platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is an Internal Developer Platform? Key Benefits &amp;amp; Features - Cortex, accessed on April 11, 2025, &lt;a href=&quot;https://www.cortex.io/post/what-is-an-internal-developer-platform&quot;&gt;https://www.cortex.io/post/what-is-an-internal-developer-platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Five reasons why an Internal Developer Platform is worth it, accessed on April 11, 2025, &lt;a href=&quot;https://platformengineering.org/blog/five-reasons-why-an-internal-developer-platform-is-worth-it&quot;&gt;https://platformengineering.org/blog/five-reasons-why-an-internal-developer-platform-is-worth-it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Navigating the Complexity of Internal Developer Platforms: A Guide for Technical Decision Makers - WSO2, accessed on April 11, 2025, &lt;a href=&quot;https://wso2.com/library/blogs/navigating-complexity-internal-developer-platforms-guide-for-technical-decision-makers/&quot;&gt;https://wso2.com/library/blogs/navigating-complexity-internal-developer-platforms-guide-for-technical-decision-makers/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spotify Backstage - everything you need to know | Humanitec, accessed on April 11, 2025, &lt;a href=&quot;https://humanitec.com/spotify-backstage-everything-you-need-to-know&quot;&gt;https://humanitec.com/spotify-backstage-everything-you-need-to-know&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Backstage.io - Platform tooling, accessed on April 11, 2025, &lt;a href=&quot;https://platformengineering.org/tools/backstage-io-spotify&quot;&gt;https://platformengineering.org/tools/backstage-io-spotify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Architecture overview | Backstage Software Catalog and Developer Platform, accessed on April 11, 2025, &lt;a href=&quot;https://backstage.io/docs/overview/architecture-overview/&quot;&gt;https://backstage.io/docs/overview/architecture-overview/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How Spotify Achieved a Voluntary 99% Internal Platform Adoption Rate - The New Stack, accessed on April 11, 2025, &lt;a href=&quot;https://thenewstack.io/how-spotify-achieved-a-voluntary-99-internal-platform-adoption-rate/&quot;&gt;https://thenewstack.io/how-spotify-achieved-a-voluntary-99-internal-platform-adoption-rate/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Principles of building an internal developer platform - AWS Prescriptive Guidance, accessed on April 11, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/prescriptive-guidance/latest/internal-developer-platform/principles.html&quot;&gt;https://docs.aws.amazon.com/prescriptive-guidance/latest/internal-developer-platform/principles.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;5 Best Practices for Building Effective Internal Developer Portals, accessed on April 11, 2025, &lt;a href=&quot;https://www.harness.io/blog/5-best-practices-for-building-effective-internal-developer-portals&quot;&gt;https://www.harness.io/blog/5-best-practices-for-building-effective-internal-developer-portals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Top 4 Predictions for Platform Engineering in 2025 | Mia-Platform, accessed on April 11, 2025, &lt;a href=&quot;https://mia-platform.eu/blog/top-4-predictions-for-platform-engineering-in-2025-and-beyond/&quot;&gt;https://mia-platform.eu/blog/top-4-predictions-for-platform-engineering-in-2025-and-beyond/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hitting the right level of abstractions when building an Internal Developer Platform, accessed on April 11, 2025, &lt;a href=&quot;https://platformengineering.org/blog/right-level-of-abstraction-internal-developer-platform&quot;&gt;https://platformengineering.org/blog/right-level-of-abstraction-internal-developer-platform&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Platform Engineering</category><category>Internal Developer Platforms</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0077-platform-engineering-building-internal-developer-platforms/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Understanding Software Versioning: A Comprehensive Guide</title><link>https://mkabumattar.com/blog/post/how-version-number-software-works/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-version-number-software-works/</guid><description>Explore the essentials of software versioning, including semantic versioning, rules, formats, and tools to manage dependencies and releases effectively.</description><pubDate>Fri, 09 May 2025 12:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Software versioning is a critical practice in software development that tracks changes and updates to a codebase. It provides a structured way to identify different iterations of a software product, ensuring clarity for developers, users, and stakeholders. However, managing versioning in systems with complex dependencies can be challenging. Overly restrictive dependency specifications may lead to &lt;em&gt;version lock&lt;/em&gt; where upgrading a package requires updating all dependent packages. Conversely, overly loose specifications can result in &lt;em&gt;version promiscuity&lt;/em&gt;, causing compatibility issues with future versions. This guide explores the principles, rules, and tools of software versioning, with a focus on Semantic Versioning (SemVer).&lt;/p&gt;
&lt;h2&gt;Why Versioning Matters&lt;/h2&gt;
&lt;p&gt;Versioning establishes a clear framework for assigning and incrementing version numbers, ensuring consistency across development teams and projects. It enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Traceability&lt;/strong&gt;: Track changes and identify specific versions of a software product.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility Management&lt;/strong&gt;: Communicate whether updates are backward-compatible or introduce breaking changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency Resolution&lt;/strong&gt;: Help package managers resolve compatible versions for dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Release Clarity&lt;/strong&gt;: Provide users and developers with clear expectations about updates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Versioning is grounded in widely adopted practices used in both open-source and proprietary software.&lt;/p&gt;
&lt;h2&gt;Semantic Versioning (SemVer) Overview&lt;/h2&gt;
&lt;p&gt;Semantic Versioning, or SemVer, is a widely adopted versioning scheme that uses a three-part number format: &lt;code&gt;MAJOR.MINOR.PATCH&lt;/code&gt;. Each segment has a specific meaning:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MAJOR&lt;/strong&gt;: Incremented for incompatible API changes (e.g., &lt;code&gt;2.0.0&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MINOR&lt;/strong&gt;: Incremented for backward-compatible feature additions (e.g., &lt;code&gt;1.1.0&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PATCH&lt;/strong&gt;: Incremented for backward-compatible bug fixes (e.g., &lt;code&gt;1.0.1&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additional labels can be used for pre-releases (e.g., &lt;code&gt;1.0.0-alpha&lt;/code&gt;) and build metadata (e.g., &lt;code&gt;1.0.0+202505091200&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;Versioning Order and Precedence&lt;/h3&gt;
&lt;p&gt;Version numbers are compared to determine precedence. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1.0.0 &amp;lt; 1.1.Luna &amp;lt; 1.1.1 &amp;lt; 2.0.0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pre-release versions have lower precedence than their associated stable release (e.g., &lt;code&gt;1.0.0-alpha &amp;lt; 1.0.0&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;Versioning Format&lt;/h3&gt;
&lt;p&gt;SemVer follows a standardized format:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stable Release&lt;/strong&gt;: &lt;code&gt;MAJOR.MINOR.PATCH&lt;/code&gt; (e.g., &lt;code&gt;1.0.0&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-release&lt;/strong&gt;: Appends a hyphen and identifier (e.g., &lt;code&gt;1.0.0-alpha.1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build Metadata&lt;/strong&gt;: Appends a plus sign and metadata (e.g., &lt;code&gt;1.0.0+build.123&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Versioning Rules&lt;/h3&gt;
&lt;p&gt;SemVer enforces strict rules to maintain consistency:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Once a version is released, its contents &lt;strong&gt;must not&lt;/strong&gt; change.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;MAJOR&lt;/code&gt; version of &lt;code&gt;0&lt;/code&gt; (e.g., &lt;code&gt;0.y.z&lt;/code&gt;) indicates unstable software where anything may change.&lt;/li&gt;
&lt;li&gt;Incrementing &lt;code&gt;MAJOR&lt;/code&gt; resets &lt;code&gt;MINOR&lt;/code&gt; and &lt;code&gt;PATCH&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Incrementing &lt;code&gt;MINOR&lt;/code&gt; resets &lt;code&gt;PATCH&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Versioning Types&lt;/h2&gt;
&lt;p&gt;Version numbers can be categorized as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Major&lt;/strong&gt;: Breaking changes that require updates to dependent code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minor&lt;/strong&gt;: New features that maintain backward compatibility.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Patch&lt;/strong&gt;: Bug fixes that maintain backward compatibility.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-release&lt;/strong&gt;: Early versions for testing (e.g., &lt;code&gt;1.0.0-beta&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build Metadata&lt;/strong&gt;: Additional data like build IDs that don’t affect precedence.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Practical Versioning Examples&lt;/h2&gt;
&lt;p&gt;Here’s how version numbers reflect different types of updates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1.0.0&lt;/code&gt;: Initial stable release.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1.0.1&lt;/code&gt;: Patch release with bug fixes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1.1.0&lt;/code&gt;: Minor release with new features.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2.0.0&lt;/code&gt;: Major release with breaking changes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1.0.0-alpha.1&lt;/code&gt;: Pre-release for testing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1.0.0+build.202505091200&lt;/code&gt;: Stable release with build metadata.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1.0.0-beta+exp.sha.5114f85&lt;/code&gt;: Pre-release with build metadata.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Versioning in Practice&lt;/h2&gt;
&lt;h3&gt;Dependency Management&lt;/h3&gt;
&lt;p&gt;Versioning ensures smooth dependency management. Package managers like npm, Composer, and Maven use version constraints to resolve compatible dependencies. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;^1.0.0&lt;/code&gt;: Allows updates to &lt;code&gt;1.x.x&lt;/code&gt; but not &lt;code&gt;2.0.0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~1.0.0&lt;/code&gt;: Allows updates to &lt;code&gt;1.0.x&lt;/code&gt; but not &lt;code&gt;1.1.0&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Release Management&lt;/h3&gt;
&lt;p&gt;Versioning integrates with release workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tagging&lt;/strong&gt;: Use Git tags (e.g., &lt;code&gt;v1.0.0&lt;/code&gt;) to mark releases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Changelogs&lt;/strong&gt;: Document changes using standards like &lt;a href=&quot;https://keepachangelog.com/&quot;&gt;Keep a Changelog&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automation&lt;/strong&gt;: Tools like &lt;a href=&quot;https://semantic-release.gitbook.io/&quot;&gt;Semantic Release&lt;/a&gt; automate version increments based on commit messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Versioning Tools&lt;/h2&gt;
&lt;p&gt;Several tools streamline versioning:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;npm&lt;/strong&gt;: Manages JavaScript package versions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composer&lt;/strong&gt;: Handles PHP dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maven&lt;/strong&gt;: Manages Java project versions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cargo&lt;/strong&gt;: Rust’s package manager.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python Packaging&lt;/strong&gt;: Supports Python version specifiers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Git Tags&lt;/strong&gt;: Marks specific commits as releases.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Best Practices for Versioning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Adopt SemVer&lt;/strong&gt;: Use SemVer for clarity and consistency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automate Versioning&lt;/strong&gt;: Use tools like Semantic Release to reduce manual errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintain Changelogs&lt;/strong&gt;: Document changes for transparency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test Pre-releases&lt;/strong&gt;: Use alpha/beta versions to gather feedback.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Communicate Breaking Changes&lt;/strong&gt;: Clearly document major version changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Software versioning, particularly Semantic Versioning, is a cornerstone of modern software development. It ensures clarity, compatibility, and effective dependency management. By understanding versioning rules, formats, and tools, developers can streamline release processes and maintain robust software ecosystems.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/&quot;&gt;Semantic Versioning 2.0.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/about-semantic-versioning&quot;&gt;NPM - Semantic Versioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://getcomposer.org/doc/articles/versions.md&quot;&gt;Composer - Versions and Constraints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://maven.apache.org/pom.html#versioning&quot;&gt;Maven - POM Reference: Versioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.atlassian.com/git/tutorials/inspecting-a-repository/git-tag&quot;&gt;Git Tagging Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://packaging.python.org/en/latest/specifications/version-specifiers/&quot;&gt;Python Packaging - Version Specifiers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://guides.rubygems.org/patterns/#semantic-versioning&quot;&gt; ]RubyGems - Semantic Versioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field&quot;&gt;Cargo (Rust) - Version Field&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.conventionalcommits.org/en/v1.0.0/&quot;&gt;Conventional Commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://keepachangelog.com/en/1.0.0/&quot;&gt;Keep a Changelog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/user/project/releases/&quot;&gt;GitLab - Releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases&quot;&gt;GitHub - Releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semantic-release.gitbook.io/semantic-release/&quot;&gt;Semantic Release&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Software Development</category><category>Versioning</category><category>DevOps</category><category>Best Practices</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0025-how-version-number-software-works/hero.jpg" length="0" type="image/jpeg"/></item><item><title>The Real Talk on Microservices vs. Monoliths</title><link>https://mkabumattar.com/blog/post/0076-the-dark-side-of-microservices-when-to-avoid-them/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/0076-the-dark-side-of-microservices-when-to-avoid-them/</guid><description>Microservices aren&apos;t always the answer. Discover the hidden complexities, challenges faced by Amazon Prime Video, and when sticking with monoliths might be the smarter architectural choice. Learn about trade-offs and avoid tech debt.</description><pubDate>Sat, 03 May 2025 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;strong&gt;The Tricky Side of Tiny Boxes: When Smaller Isn&amp;#39;t Always Better&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;So, microservices, right? They&amp;#39;re all the rage in the software world these days. Everyone&amp;#39;s buzzing about how they make things super flexible and let different parts of your app grow as much as they need to. And yeah, that sounds awesome when you hear it at a conference. But honestly, sometimes I think we get so caught up in the excitement that we forget to ask ourselves a pretty important question: &amp;quot;Hey, is this actually going to make our lives easier, or just... you know, &lt;em&gt;more complicated&lt;/em&gt;?&amp;quot;&lt;/p&gt;
&lt;p&gt;Think about it. You start with one big application – a &lt;strong&gt;monolith&lt;/strong&gt;, as the fancy folks call it – that basically does everything in one place. Then, you chop it up into a bunch of little pieces, these &lt;strong&gt;microservices&lt;/strong&gt;, that all have to talk to each other over the network. Suddenly, what used to be a simple chat inside one program turns into a bunch of phone calls between different programs. And you know how phone calls can go – dropped connections, misunderstandings, the whole shebang.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;More Pieces, More Problems? Does Splitting Up Always Simplify?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;One of the biggest things I&amp;#39;ve seen is that going from one big thing to a bunch of small things can actually make your life way more complicated. Instead of dealing with &lt;em&gt;one&lt;/em&gt; application, you&amp;#39;ve got a whole bunch of them. That means you&amp;#39;ve got to worry about growing each one separately, making sure all their little doorways (they call &amp;#39;em APIs) are secure, keeping track of different versions of everything, and deploying all these little bits and pieces. It can feel like trying to herd cats, right?&lt;/p&gt;
&lt;p&gt;And let&amp;#39;s not even get started on getting these little guys to talk to each other nicely. You make a change in one, and suddenly another one starts acting weird. It&amp;#39;s like trying to coordinate a bunch of musicians who are all playing their own songs at the same time. You need a really good conductor – or, you know, some serious coordination – to make sure it sounds like music and not just noise.&lt;/p&gt;
&lt;p&gt;Testing becomes a whole new ballgame, too. Instead of just testing one big thing, you&amp;#39;ve got to test each little piece &lt;em&gt;and&lt;/em&gt; how they all work together. That can mean setting up all sorts of special testing areas and spending a ton of time just making sure everything plays nice. And when something goes wrong? Forget about it. Trying to fix a problem that jumps across five different little services can feel like trying to find a single bad wire in a giant, tangled mess. You&amp;#39;re digging through logs from all over the place, trying to piece together what went wrong where.&lt;/p&gt;
&lt;p&gt;Then there&amp;#39;s just the sheer number of moving parts. More services mean more servers, more network connections, more things that can potentially break. And managing all of that? It takes a lot more effort and can really add to your team&amp;#39;s workload. Plus, you&amp;#39;ve got to figure out how these services are going to talk to each other – are they using fancy REST calls? Maybe some other kind of messaging? Each way has its own quirks and can add its own layer of complexity.&lt;/p&gt;
&lt;p&gt;And don&amp;#39;t even get me started on the people side of things. You might have different teams owning different microservices, which sounds great for independence, but it also means you need really clear rules about how these services interact. If teams aren&amp;#39;t on the same page, you can end up with a real mess of different technologies and ways of doing things, which just makes everything harder down the line.&lt;/p&gt;
&lt;p&gt;Finally, let&amp;#39;s talk about the data. When you split up a monolith, you often end up splitting up your data too. Suddenly, information that used to be in one place is spread across multiple databases. Keeping everything consistent and making sure transactions work correctly across all these different places? That&amp;#39;s a serious headache and requires some pretty clever solutions.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Wait, Monoliths Aren&amp;#39;t All Bad? Why the &amp;quot;Old Way&amp;quot; Still Has Its Perks&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;You know, with all this talk about how great microservices are, it&amp;#39;s easy to forget that the &amp;quot;old way&amp;quot; – building &lt;strong&gt;monoliths&lt;/strong&gt; – still has a lot going for it. For smaller projects, especially when you&amp;#39;re just starting out and have a small team, a monolith can be way simpler and faster to build. You&amp;#39;ve got one codebase, one place to deploy, and things are generally easier to understand. It&amp;#39;s like having all your tools in one toolbox instead of scattered across a whole workshop.&lt;/p&gt;
&lt;p&gt;Getting a monolith up and running is usually pretty straightforward. You just deploy the whole thing to one place, and bam, you&amp;#39;re good to go. And when something goes wrong, you&amp;#39;re usually looking in one set of logs, in one environment. Makes fixing things a whole lot easier, especially when you&amp;#39;re not dealing with a bunch of network calls and different services.&lt;/p&gt;
&lt;p&gt;Plus, sometimes a monolith can actually be faster. When different parts of your application need to talk to each other a lot, doing it within the same application is way quicker than sending requests over a network between different microservices. It&amp;#39;s like having a conversation with someone sitting next to you versus having to call them on the phone every time you need to say something.&lt;/p&gt;
&lt;p&gt;And let&amp;#39;s be real, for applications that aren&amp;#39;t changing all the time or don&amp;#39;t need to handle massive amounts of traffic, a monolith can be perfectly fine. Why introduce all that extra complexity if you don&amp;#39;t really need it? It&amp;#39;s like buying a huge truck when all you need is a bicycle.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Amazon Prime Video&amp;#39;s Big U-Turn: Even the Big Guys Face Microservice Mayhem&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The story of &lt;strong&gt;Amazon Prime Video&lt;/strong&gt; is actually a really interesting one when it comes to microservices. You&amp;#39;d think a tech giant like that would have it all figured out, right? They started going big on microservices to handle their massive scale and make sure different parts of their video streaming service could grow independently.&lt;/p&gt;
&lt;p&gt;But as they got bigger and bigger, they started running into some serious issues. All that back-and-forth communication between hundreds of tiny services started causing noticeable delays, even if it was just milliseconds. When you&amp;#39;ve got millions of people watching videos at the same time, even tiny delays can make a big difference in how smooth things feel. Managing all those services – keeping an eye on them, deploying updates, and figuring out what went wrong when something broke – became a huge headache.&lt;/p&gt;
&lt;p&gt;And here&amp;#39;s the kicker: for one of their key services that analyzed video quality, they actually went &lt;em&gt;back&lt;/em&gt; to a &lt;strong&gt;monolithic&lt;/strong&gt; design! It turned out that the microservices approach they had used was costing them a fortune in cloud bills because of all the little interactions and data transfers. By putting it all back into one place, they managed to slash their AWS bill for that service by a whopping 90%!&lt;/p&gt;
&lt;p&gt;Even though they were using fancy &amp;quot;serverless&amp;quot; microservices that were supposed to scale automatically, they still hit roadblocks in managing all the coordination. And for some of the really core parts of their system, like playing videos and recommending what to watch, they found that they needed things to be really tightly integrated, which was actually easier to achieve with a more together approach.&lt;/p&gt;
&lt;p&gt;So, even Amazon Prime Video, with all their smart engineers and resources, realized that &lt;strong&gt;microservices&lt;/strong&gt; aren&amp;#39;t always the golden ticket. They ended up going with a mix – using a monolith for some of the really critical, performance-sensitive stuff and keeping microservices for other things like billing and managing their content library. It just goes to show you that there&amp;#39;s no one-size-fits-all answer in tech.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;The Sneaky Trap of Tech Debt: How Tiny Services Can Lead to Big Problems Later&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;You&amp;#39;d think breaking things down into smaller pieces would help you manage &lt;strong&gt;tech debt&lt;/strong&gt;, right? In some ways, it can. But &lt;strong&gt;microservices&lt;/strong&gt; can also create their own special brand of technical mess if you&amp;#39;re not careful. Because everyone&amp;#39;s doing their own thing in their little service, you can end up with different teams using totally different technologies, frameworks, and ways of coding. Over time, that can make it really hard for different parts of your system to work together smoothly and can lead to a lot of extra work when you need to make changes across multiple services.&lt;/p&gt;
&lt;p&gt;If the communication between your microservices isn&amp;#39;t designed well, you can end up with services that are really tightly connected, even though they&amp;#39;re supposed to be independent. That means if you change one, you might break a bunch of others, which kind of defeats the whole purpose of having separate services in the first place. And if you don&amp;#39;t draw the lines between your services correctly, you can end up with either a million tiny services that are constantly chattering back and forth, or services that are still too big and clunky, just now they&amp;#39;re distributed.&lt;/p&gt;
&lt;p&gt;Then there&amp;#39;s all the extra infrastructure and tooling you need for deploying, keeping an eye on, and scaling all these individual services. If you don&amp;#39;t invest in good tools and practices, that can become a huge source of &lt;strong&gt;tech debt&lt;/strong&gt; down the road.&lt;/p&gt;
&lt;p&gt;One of the worst things that can happen is what people call a &amp;quot;distributed monolith.&amp;quot; That&amp;#39;s when you have a bunch of microservices that are so tightly linked that they basically act like one big, clunky application, but with all the added headaches of network communication. You get all the downsides of a monolith and all the downsides of microservices – a real recipe for disaster! And because everything&amp;#39;s spread out, it can be harder to even realize you&amp;#39;ve got this problem and to clean it up. So, while microservices can help you manage tech debt in some ways, you&amp;#39;ve got to be really careful not to create a whole new set of problems.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;The Give and Take: Weighing the Pros and Cons of Tiny Services&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Choosing between &lt;strong&gt;microservices&lt;/strong&gt; and &lt;strong&gt;monoliths&lt;/strong&gt; really comes down to understanding the &lt;strong&gt;trade-offs&lt;/strong&gt;. There&amp;#39;s no right or wrong answer that fits every situation. Each approach has its pluses and minuses, and you&amp;#39;ve got to figure out what&amp;#39;s most important for your specific project.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Monoliths&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Microservices&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Getting Started&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usually simpler and faster&lt;/td&gt;
&lt;td&gt;Can be more complex to set up initially&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Putting it Out There&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easier to deploy at first&lt;/td&gt;
&lt;td&gt;Requires more coordination for multiple services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dealing with Growth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can be harder to scale specific parts&lt;/td&gt;
&lt;td&gt;Easier to scale individual services as needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Keeping Things Running&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One failure can bring down everything&lt;/td&gt;
&lt;td&gt;Problems in one service are less likely to affect others&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mixing Technologies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usually stuck with one main tech stack&lt;/td&gt;
&lt;td&gt;More freedom to use different tech for different services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Working Together&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easier for small, close-knit teams&lt;/td&gt;
&lt;td&gt;Can enable more independent teams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Keeping Things Tidy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can become harder to maintain as it grows&lt;/td&gt;
&lt;td&gt;Easier to maintain smaller, focused services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overall Complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Centralized, but can get messy over time&lt;/td&gt;
&lt;td&gt;Distributed, requires careful planning and management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Initial Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Often lower to start&lt;/td&gt;
&lt;td&gt;Can be higher due to infrastructure and tooling needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost Over Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can become expensive to scale the whole thing&lt;/td&gt;
&lt;td&gt;Costs can be more aligned with actual usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Getting Features Out&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can be faster for simple apps&lt;/td&gt;
&lt;td&gt;Can be faster for individual features once the system is set up&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Basically, &lt;strong&gt;monoliths&lt;/strong&gt; are often easier to get started with and deploy initially, especially for smaller teams and simpler applications. But as things grow and you need to handle more traffic or want to update different parts of your app independently, they can become a bottleneck. &lt;strong&gt;Microservices&lt;/strong&gt;, on the other hand, can be great for scaling and letting different teams work independently, but they come with a lot more initial complexity in setting them up and managing all the different pieces. You get more flexibility in choosing technologies, but you also have to deal with the headaches of distributed systems. The cost can also be a factor – while a monolith might be cheaper to start, scaling it can become expensive, whereas microservices might have a higher initial cost but scale more efficiently in the long run. It&amp;#39;s all about finding the right balance for your specific situation.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;So, When Should You Just Say &amp;quot;No Thanks&amp;quot; to Microservices?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;A lot of folks jump on the &lt;strong&gt;microservices&lt;/strong&gt; bandwagon without really thinking about whether it&amp;#39;s the right move for them. But there are definitely times when it&amp;#39;s better to just steer clear.&lt;/p&gt;
&lt;Accordion client:load title=&quot;If you&apos;ve got a small team&quot;&gt;
  Honestly, dealing with all the extra overhead of microservices can really slow
  you down. You might spend more time managing the infrastructure and
  communication between services than actually building features. A
  **monolithic** approach is often much more manageable when you have fewer
  people.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;If your application isn&amp;#39;t going to be the next Facebook or Amazon&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  You probably don&amp;#39;t need the extreme scalability that microservices offer. If
  you&amp;#39;re not expecting massive growth, the added complexity might not be worth
  it. A simpler setup can often handle moderate loads just fine.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;If your team is new to distributed systems&quot;&gt;
  Diving headfirst into microservices can be a recipe for disaster. There&apos;s a
  lot to learn about how to design, build, deploy, and operate distributed
  applications, and making mistakes can be costly. It&apos;s often better to start
  with something simpler and gradually evolve if needed.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;There are also some types of applications that just aren&amp;#39;t a great fit for microservices&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  For example, if you have a lot of tightly connected parts that always need to
  be deployed together, splitting them into separate services might just add
  unnecessary complexity without much benefit. And for quick little
  proof-of-concept projects, the overhead of setting up a microservices
  architecture is usually overkill.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;So, when does all that microservices complexity outweigh the benefits?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  It&amp;#39;s when you&amp;#39;re spending more time and effort managing the distributed system
  than you&amp;#39;re getting back in terms of scalability, flexibility, or resilience.
  If the complexity is slowing down your development, making your system less
  stable, or costing you a fortune without providing real advantages for your
  specific needs, then it&amp;#39;s probably time to reconsider.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Making the Smart Choice: How to Pick the Right Architecture for You&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Choosing the right &lt;strong&gt;architecture&lt;/strong&gt; is a big deal. It can set you up for success or lead to a world of pain down the road. Here are a few things to keep in mind when you&amp;#39;re making this decision:&lt;/p&gt;
&lt;p&gt;For a lot of projects, especially when you&amp;#39;re just starting out, it makes sense to begin with a &lt;strong&gt;monolithic&lt;/strong&gt; architecture. It&amp;#39;s simpler to understand and develop, and you can always break things down later if you really need to. Think of it as starting with a solid foundation.&lt;/p&gt;
&lt;p&gt;A &amp;quot;modular monolith&amp;quot; can also be a really good middle ground. It&amp;#39;s still one application, but you design it in a way that different parts are really separate and don&amp;#39;t depend on each other too much. This can give you some of the flexibility of microservices without all the distributed complexity, and it can make it easier to split things out into separate services later if you need to.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s super important to pick an architecture that your team actually knows how to work with. If your team doesn&amp;#39;t have a lot of experience with distributed systems and cloud technologies, starting with a complex microservices setup is probably not a good idea.&lt;/p&gt;
&lt;p&gt;Really think hard about how much your application needs to scale. If you&amp;#39;re not expecting massive growth, don&amp;#39;t over-engineer things from the start. You can always optimize for scale later if it becomes necessary.&lt;/p&gt;
&lt;p&gt;Consider how complicated it will be to deploy and manage your application. Microservices require a lot more infrastructure and tooling, so make sure your team is ready for that.&lt;/p&gt;
&lt;p&gt;If you do decide to go with microservices, make sure you clearly define the boundaries of each service based on what they do in the business. This helps avoid creating services that are too tightly connected or too small. And from day one, make sure you have good systems in place for monitoring and tracking what&amp;#39;s going on in all your services.&lt;/p&gt;
&lt;p&gt;The bottom line is, don&amp;#39;t just jump on the microservices bandwagon because it&amp;#39;s the cool thing to do. Really think about your specific needs, your team&amp;#39;s skills, and the long-term goals for your application. Sometimes, the simpler path is the better path.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Wrapping Up: Choosing Your Tech Path Wisely&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;So, while &lt;strong&gt;microservices&lt;/strong&gt; can be a powerful tool for building scalable and flexible applications, they&amp;#39;re definitely not a magic bullet. They come with a significant increase in &lt;strong&gt;complexity&lt;/strong&gt; and can lead to a whole new set of challenges if you&amp;#39;re not careful. The experience of &lt;strong&gt;Amazon Prime Video&lt;/strong&gt; shows us that even the biggest players can run into trouble and sometimes need to rethink their &lt;strong&gt;architecture&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s crucial to take a hard look at the potential downsides and really understand the &lt;strong&gt;trade-offs&lt;/strong&gt; involved. For many applications, especially smaller ones or those with less demanding scaling needs, sticking with a &lt;strong&gt;monolithic&lt;/strong&gt; approach or exploring a modular monolith might be the smarter and more efficient choice.&lt;/p&gt;
&lt;p&gt;Ultimately, the best architectural decision is the one that aligns with your specific requirements, your team&amp;#39;s expertise, and your long-term goals. Don&amp;#39;t just follow the hype; choose wisely and build something that works for &lt;em&gt;you&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;5 Advantages of Microservices [+ Disadvantages] | Atlassian, accessed on April 11, 2025, &lt;a href=&quot;https://www.atlassian.com/microservices/cloud-computing/advantages-of-microservices&quot;&gt;https://www.atlassian.com/microservices/cloud-computing/advantages-of-microservices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tyk.io, accessed on April 11, 2025, &lt;a href=&quot;https://tyk.io/blog/navigating-and-managing-microservices-complexity-tyk/#:~:text=Common%20sources%20of%20complexity%20in%20microservices&amp;text=Being%20able%20to%20scale%20each,they%20become%20coupled%2C%20however%20loosely.&quot;&gt;https://tyk.io/blog/navigating-and-managing-microservices-complexity-tyk/#:~:text=Common%20sources%20of%20complexity%20in%20microservices&amp;amp;text=Being%20able%20to%20scale%20each,they%20become%20coupled%2C%20however%20loosely.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;7 Disadvantages of Microservices (+ Advantages) (2024) - Shopify, accessed on April 11, 2025, &lt;a href=&quot;https://www.shopify.com/enterprise/blog/disadvantages-microservices&quot;&gt;https://www.shopify.com/enterprise/blog/disadvantages-microservices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microservices Testing: Architecture Challenges &amp;amp; Strategies - ACCELQ, accessed on April 11, 2025, &lt;a href=&quot;https://www.accelq.com/blog/understanding-microservices-architecture-and-its-testing-challenges/&quot;&gt;https://www.accelq.com/blog/understanding-microservices-architecture-and-its-testing-challenges/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;10 Microservices Architecture Challenges for System Design Interviews - DEV Community, accessed on April 11, 2025, &lt;a href=&quot;https://dev.to/somadevtoo/10-microservices-architecture-challenges-for-system-design-interviews-6g0&quot;&gt;https://dev.to/somadevtoo/10-microservices-architecture-challenges-for-system-design-interviews-6g0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Avoid Microservice Anti-Patterns - vFunction, accessed on April 11, 2025, &lt;a href=&quot;https://vfunction.com/blog/how-to-avoid-microservices-anti-patterns/&quot;&gt;https://vfunction.com/blog/how-to-avoid-microservices-anti-patterns/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Monolithic vs Microservices - Difference Between Software ... - AWS, accessed on April 11, 2025, &lt;a href=&quot;https://aws.amazon.com/compare/the-difference-between-monolithic-and-microservices-architecture/&quot;&gt;https://aws.amazon.com/compare/the-difference-between-monolithic-and-microservices-architecture/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Why Amazon Prime Video Reverted to a Monolith: A Case Study on ..., accessed on April 11, 2025, &lt;a href=&quot;https://medium.com/@hellomeenu1/why-amazon-prime-video-reverted-to-a-monolith-a-case-study-on-cloud-architecture-evolution-bd2582b438a5&quot;&gt;https://medium.com/@hellomeenu1/why-amazon-prime-video-reverted-to-a-monolith-a-case-study-on-cloud-architecture-evolution-bd2582b438a5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Are Microservices? Architecture, Challenges, and Tips | Solo.io, accessed on April 11, 2025, &lt;a href=&quot;https://www.solo.io/topics/microservices&quot;&gt;https://www.solo.io/topics/microservices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Back to the Monolith: Why Did Amazon Dump Microservices ..., accessed on April 11, 2025, &lt;a href=&quot;https://nordicapis.com/back-to-the-monolith-why-did-amazon-dump-microservices/&quot;&gt;https://nordicapis.com/back-to-the-monolith-why-did-amazon-dump-microservices/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon Ditches Microservices for Monolith: Decoding Prime Video&amp;#39;s ..., accessed on April 11, 2025, &lt;a href=&quot;https://amplication.com/blog/amazon-ditches-microservices-for-monolith-decoding-prime-videos-architectural-shift&quot;&gt;https://amplication.com/blog/amazon-ditches-microservices-for-monolith-decoding-prime-videos-architectural-shift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Debunking Misconceptions: Amazon Prime Video&amp;#39;s Approach to ..., accessed on April 11, 2025, &lt;a href=&quot;https://www.catchpoint.com/blog/debunking-misconceptions-amazon-prime-videos-approach-to-microservices-and-serverless&quot;&gt;https://www.catchpoint.com/blog/debunking-misconceptions-amazon-prime-videos-approach-to-microservices-and-serverless&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Software Architecture</category><category>Microservices</category><category>Monoliths</category><category>System Design</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0076-the-dark-side-of-microservices-when-to-avoid-them/hero.jpg" length="0" type="image/jpeg"/></item><item><title>GitHub Actions vs. GitLab CI for Monorepos: Which One Wins?</title><link>https://mkabumattar.com/blog/post/github-actions-vs-gitlab-ci-for-monorepos/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/github-actions-vs-gitlab-ci-for-monorepos/</guid><description>Comparing GitHub Actions and GitLab CI for monorepo management. Analyze features, CI/CD pipelines, parallel jobs, caching, secrets management, and real-world experiences to choose the best platform.</description><pubDate>Sat, 26 Apr 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The world of building software is always changing, and how teams organize their code can really affect how well they work. One way that&amp;#39;s become pretty popular is using a monorepo – that&amp;#39;s just keeping all the code for different projects in one big place. This can make things simpler when you&amp;#39;re dealing with shared code, keeping track of changes, and having different teams work together. But, if you&amp;#39;ve got a monorepo, you need a good system to automatically build, test, and deliver your software whenever you make a change. This is where CI/CD comes in, and it needs to be smart enough to handle the complexity of a monorepo. The goal is to make sure things keep moving fast and the code stays good.&lt;/p&gt;
&lt;p&gt;When it comes to CI/CD platforms, GitHub Actions and GitLab CI are two of the big names out there. They both help you automate your software tasks. In this blog post, we&amp;#39;re going to take a good look at how GitHub Actions and GitLab CI stack up specifically for managing monorepos. This should help you figure out which one might be the best fit for your team.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What&amp;#39;s Under the Hood? Key Features Compared&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When you&amp;#39;re picking a CI/CD tool for a monorepo, there are some important things to think about. Let&amp;#39;s see how GitHub Actions and GitLab CI handle these.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Setting Up Your Workflows/Pipelines&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;With GitHub Actions, you tell it what to do using files written in something called YAML. These files live in a special folder in your project called .github/workflows. You can set these workflows to run when all sorts of things happen, like when someone pushes code, opens a pull request, or on a schedule. This gives you a lot of freedom to automate just about anything. Each workflow is made up of one or more jobs, and each job has a list of steps that get done one after the other.&lt;/p&gt;
&lt;p&gt;GitLab CI does things a bit differently. It uses one YAML file called .gitlab-ci.yml that sits at the very top of your project. This file lays out all the stages of your process, like building, testing, and deploying, and the jobs that run in each stage. In the past, everything had to be in this one file. But, because monorepos can be complex, GitLab CI added a way to include other configuration files based on what parts of the code have changed. This lets you run more specific pipelines.&lt;/p&gt;
&lt;p&gt;So, the way you set up your workflows or pipelines is a bit different. GitHub Actions uses separate files for different workflows, which can help keep things organized, especially in big monorepos with lots of projects. It&amp;#39;s easier to see the specific automation for different parts of your code. GitLab CI&amp;#39;s single file approach, now with the ability to include others conditionally, gives you a more central view of your whole CI/CD process. And being able to include files based on changes makes it more targeted for monorepos.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Getting Extra Help: Ecosystem and Extensibility&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitHub Actions has a really lively community and a big marketplace called the GitHub Actions Marketplace. Here, you can find tons of pre-built actions created by the community and by GitHub itself. These actions can do all sorts of things and connect to many different tools and services. This means you can easily add features to your CI/CD process without having to write a lot of code yourself. Plus, you can create your own actions and share them with your team or the wider community.&lt;/p&gt;
&lt;p&gt;GitLab CI doesn&amp;#39;t have a marketplace like that, but it comes with a lot of features built right in. Its Auto DevOps feature can automatically handle many common CI/CD tasks, like building, testing, and deploying. It also works really well with other parts of GitLab, like security scanning, managing your build results, and handling releases. If you need to extend GitLab CI, you usually do it by writing custom scripts in your jobs or by using Docker images to create consistent and isolated environments for your builds.&lt;/p&gt;
&lt;p&gt;GitHub Actions really shines when it comes to being flexible and connecting with lots of different tools and services, thanks to its marketplace. GitLab CI offers a more integrated experience if you&amp;#39;re already using GitLab for everything, with many essential CI/CD features ready to go and working smoothly with the rest of GitLab. Which approach is better often depends on what your monorepo needs and whether you&amp;#39;d rather use pre-built integrations or have everything more tightly connected within one platform.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Which Systems Can They Run On? Operating System Support&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitHub Actions gives you good support for running its hosted runners on different operating systems, including Linux, Windows Server, and macOS. This is great because it means you can build and test the different parts of your monorepo on the exact platforms they&amp;#39;re meant to run on, without having to manage your own servers.&lt;/p&gt;
&lt;p&gt;GitLab CI mainly uses Linux runners as its standard option. They are working on expanding their support, but macOS and Windows runners are currently in beta.&lt;/p&gt;
&lt;p&gt;This difference in operating system support can be a big deal if your monorepo has projects that need to be built or tested on specific platforms. The more mature and wider support from GitHub Actions might make it an easier choice if you need to work with Windows or macOS. While GitLab CI is catching up, the fact that macOS and Windows are in beta might mean they&amp;#39;re not as stable or have some limitations you need to be aware of.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Running Your Own Show: Self-Hosted Runner Support&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Both GitHub Actions and GitLab CI know that sometimes you need more control over your build environment, so they both let you use your own servers as runners. This means you can set up and manage your own infrastructure to run your CI/CD jobs, giving you more say over the hardware, software, and network settings. This can be really important for large monorepos that might need a lot of computing power or have specific security requirements. Having the option to use self-hosted runners ensures you can tailor your CI/CD setup to exactly what your monorepo needs, no matter which platform you pick.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;GitLab CI&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Key Monorepo Relevance&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Workflow/Pipeline Definition&lt;/td&gt;
&lt;td&gt;YAML in .github/workflows (multiple files)&lt;/td&gt;
&lt;td&gt;YAML in .gitlab-ci.yml (single file with includes)&lt;/td&gt;
&lt;td&gt;Modularity vs. Centralization; Being able to run specific builds based on what changed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ecosystem and Extensibility&lt;/td&gt;
&lt;td&gt;Extensive Marketplace of pre-built actions&lt;/td&gt;
&lt;td&gt;Built-in Auto DevOps; Seamless GitLab integration&lt;/td&gt;
&lt;td&gt;Easy to connect to lots of tools vs. Everything working together within one platform.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating System Support&lt;/td&gt;
&lt;td&gt;Linux, Windows, macOS (stable)&lt;/td&gt;
&lt;td&gt;Linux (stable), macOS, Windows (beta)&lt;/td&gt;
&lt;td&gt;Ability to build and test on the right platforms for all the different projects in your monorepo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-Hosted Runners&lt;/td&gt;
&lt;td&gt;Fully supported&lt;/td&gt;
&lt;td&gt;Fully supported&lt;/td&gt;
&lt;td&gt;Flexibility to set up your own build servers to handle the performance and specific needs of large monorepos.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change Detection&lt;/td&gt;
&lt;td&gt;Path filters in workflow triggers, custom scripts&lt;/td&gt;
&lt;td&gt;`rules:changes` in jobs/includes&lt;/td&gt;
&lt;td&gt;Being able to only trigger builds for the projects that were actually changed in the monorepo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel Execution&lt;/td&gt;
&lt;td&gt;Parallel jobs by default; concurrency control&lt;/td&gt;
&lt;td&gt;Parallel jobs in stages by default; needs, parallel&lt;/td&gt;
&lt;td&gt;Speeding up the whole process for large monorepos with many tasks by running things at the same time.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caching&lt;/td&gt;
&lt;td&gt;cache action; Package manager caching; Remote caching&lt;/td&gt;
&lt;td&gt;cache keyword; Content-based caching; Distributed caching&lt;/td&gt;
&lt;td&gt;Making builds faster by reusing things like downloaded libraries and build results across different projects and runs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets Management&lt;/td&gt;
&lt;td&gt;Repository, environment, organization secrets; OIDC&lt;/td&gt;
&lt;td&gt;CI/CD variables; Integration with external providers&lt;/td&gt;
&lt;td&gt;Keeping sensitive information needed for builds and deployments secure within the monorepo.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;How They Handle Pipelines: CI/CD Strategies for Monorepos&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When you&amp;#39;re dealing with monorepos, it&amp;#39;s super important that your CI/CD pipelines are both efficient and can handle growth. Let&amp;#39;s see how GitHub Actions and GitLab CI tackle this.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Efficiency and Growth for Monorepos&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitHub Actions helps keep things efficient in monorepos by letting you set up path filters right in the workflow triggers. This means you can tell a workflow to only run if changes are made in specific folders that it cares about. This is really useful for not wasting resources on building and testing parts of the monorepo that haven&amp;#39;t been touched, which helps it scale as your monorepo gets bigger and more complex.&lt;/p&gt;
&lt;p&gt;GitLab CI also focuses on efficiency and scalability for monorepos by using the include keyword along with something called &lt;code&gt;rules:changes&lt;/code&gt;. This is a powerful feature that lets you conditionally include specific CI/CD configuration files based on changes in certain folders of your monorepo. For example, if you only change something in the frontend folder, only the CI/CD stuff related to the frontend will be included and run. Plus, GitLab CI supports parent-child pipelines, which means you can break down big, complex monorepo workflows into smaller, easier-to-manage pieces, making things more scalable and easier to maintain.&lt;/p&gt;
&lt;p&gt;Both platforms give you good ways to handle CI/CD pipelines in monorepos by letting you run things only when specific files change. This is key for keeping performance up and making sure things can grow with your repository. GitHub Actions uses path-based workflow triggers, which is a pretty straightforward way to control when a workflow runs. GitLab CI, with its conditional includes and parent-child pipelines, offers a more structured and declarative approach to managing pipelines for different parts of your application within the main configuration, giving you flexibility and better organization for more complicated situations.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Change Detection&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitHub Actions offers the paths filter within the on.push event configuration as a primary mechanism for change detection in monorepos. By listing specific directories or file patterns, developers can ensure that a workflow is only triggered when changes are pushed to those locations. For more intricate change detection requirements, teams can also incorporate custom scripts within their workflows to analyze Git history and identify modified files or directories.&lt;/p&gt;
&lt;p&gt;GitLab CI provides the &lt;code&gt;rules:changes&lt;/code&gt; keyword, which can be applied within job definitions or in conjunction with the include directive to establish conditions based on file modifications. This allows for a high degree of flexibility in triggering jobs or including specific configurations only when relevant changes are detected in the specified paths within the monorepo.&lt;/p&gt;
&lt;p&gt;Both platforms offer robust and adaptable methods for detecting changes within a monorepo, which is crucial for triggering targeted CI/CD processes only when necessary. This capability is paramount for efficient resource utilization in monorepo environments. The paths filter in GitHub Actions provides a direct and easily understandable way to define triggers based on file changes. GitLab CI&amp;#39;s &lt;code&gt;rules:changes&lt;/code&gt; offers greater versatility as it can be used at various levels within the pipeline definition, allowing for more nuanced control over when jobs or included configurations are executed based on file modifications.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Example Configurations&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Numerous examples illustrate how to configure GitHub Actions for monorepos. Workflows can be set up to trigger specific jobs for different services based on changes in their respective directories. For instance, a workflow responsible for building the backend application might only run when changes are detected within the backend directory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GitHub Actions Workflow Example:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To build and test only when changes occur in the backend folder, you can define a workflow like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Backend CI
on:
  push:
    branches: [main]
    paths:
      - &amp;#39;backend/**&amp;#39;
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: &amp;#39;17&amp;#39;
          distribution: &amp;#39;temurin&amp;#39;
      - name: Build with Maven
        run: cd backend &amp;amp;&amp;amp; mvn clean install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, GitLab CI provides clear configuration patterns for managing CI/CD in monorepos. Examples demonstrate the use of the &lt;code&gt;include&lt;/code&gt; keyword with &lt;code&gt;rules:changes&lt;/code&gt; to trigger different application-specific pipelines based on modifications in their corresponding directories. For example, changes in a &lt;code&gt;java/&lt;/code&gt; directory can trigger the inclusion and execution of a pipeline defined in &lt;code&gt;/java/.gitlab-ci.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GitLab CI Workflow Example:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To include a specific CI configuration file only when changes are detected in the &lt;code&gt;java&lt;/code&gt; directory, your &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; might look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;include:
  - local: &amp;#39;/java/.gitlab-ci.yml&amp;#39;
    rules:
      - changes:
          - &amp;#39;java/**/*&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The availability of these practical examples for both platforms simplifies the process for users to understand and implement change-based triggering in their own monorepo CI/CD pipelines, ultimately reducing the overhead of running unnecessary jobs.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Concurrency Control: How Do Both Platforms Implement and Manage Parallel Jobs for Monorepos?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Parallel execution of jobs is essential for reducing the overall pipeline duration, especially in large monorepos with many build and test tasks. Both GitHub Actions and GitLab CI offer robust capabilities for managing parallel execution.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Parallel Execution Capabilities&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitHub Actions allows multiple jobs within a single workflow to run in parallel by default, effectively utilizing the resources of the chosen runner. To manage resource consumption and prevent potential race conditions, the &lt;code&gt;concurrency&lt;/code&gt; keyword can be used at the workflow or job level to limit the number of simultaneous executions. This feature ensures that only one instance of a specific workflow or job group runs at any given time, which can be critical for tasks like deployments.&lt;/p&gt;
&lt;p&gt;GitLab CI also executes jobs within the same stage in parallel by default, optimizing the time it takes for a pipeline to complete. For more complex scenarios, the &lt;code&gt;parallel&lt;/code&gt; keyword enables parallel execution of matrix builds, allowing the same job to run concurrently with different configurations. Additionally, the &lt;code&gt;needs&lt;/code&gt; keyword provides a mechanism to define dependencies between jobs, influencing the order of execution and implicitly managing concurrency across different stages. Jobs that do not have any unmet &lt;code&gt;needs&lt;/code&gt; and are in the same stage will run in parallel.&lt;/p&gt;
&lt;p&gt;Both platforms provide effective ways to achieve parallel execution of CI/CD jobs, which is particularly important for monorepos where build and test suites can be extensive. They also offer features to control and manage concurrency based on the specific requirements of the workflow and the resources available.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Managing Parallelism in Monorepos&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In a monorepo context, GitHub Actions allows teams to define multiple workflows, each targeting different parts of the repository. These workflows can then run in parallel when triggered by changes in their respective areas. The &lt;code&gt;concurrency&lt;/code&gt; setting can be particularly valuable for controlling parallel deployments, ensuring that critical environments are not overwhelmed by simultaneous deployment processes.&lt;/p&gt;
&lt;p&gt;GitLab CI supports parent-child pipelines, which enable a parent pipeline to trigger multiple independent child pipelines for different projects or components within the monorepo, allowing for parallel processing of these separate entities. Furthermore, the parallel keyword within job definitions can be utilized to run the same job concurrently for different packages or configurations within the monorepo, such as running tests for multiple sub-projects in parallel.&lt;/p&gt;
&lt;p&gt;Both platforms offer effective strategies for managing parallelism within a monorepo, enabling concurrent building, testing, and deployment of different components or projects residing within the single repository. This capability is crucial for maintaining efficient CI/CD workflows in complex monorepo environments.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Performance Considerations&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The performance of parallel jobs in a monorepo on GitHub Actions can be influenced by the resources available to the chosen runners, whether they are GitHub-hosted or self-hosted. Additionally, in very large monorepos with a high volume of parallel tasks, teams might encounter limitations related to API call quotas, which could impact the overall efficiency of the CI/CD process.&lt;/p&gt;
&lt;p&gt;For GitLab CI, the performance of parallel jobs can be affected by the overall size of the monorepo, as each parallel job might initiate its own set of Git operations like cloning or fetching. The capacity and configuration of the GitLab Runner infrastructure being used also play a significant role in the performance of parallel execution.&lt;/p&gt;
&lt;p&gt;Achieving optimal performance with parallel jobs in monorepos on both platforms requires careful consideration of the underlying infrastructure, the availability of resources, and potential platform-specific limitations that might arise at scale. Teams should monitor their CI/CD pipeline performance and consider strategies to optimize their configurations and infrastructure to avoid bottlenecks.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Caching for Speed: How Effective Are the Caching Mechanisms in Optimizing Build Times for Large Monorepos?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Caching is a critical aspect of optimizing build times in CI/CD pipelines, particularly for large monorepos where dependencies and build artifacts can be substantial. Both GitHub Actions and GitLab CI provide robust caching mechanisms.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Caching Mechanisms&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitHub Actions offers a dedicated &lt;code&gt;cache&lt;/code&gt; action that allows users to store and restore dependencies and build outputs across different workflow runs. This action uses a key to identify the cache and supports fallback keys for scenarios where an exact match is not found. GitHub Actions also provides specific setup actions for various package managers (e.g., npm, Maven, Gradle) that often include built-in caching capabilities. Furthermore, GitHub Actions supports remote caching solutions like Turborepo, enabling the sharing of build artifacts across different runners and even repositories, which can be highly beneficial for monorepo setups. However, it&amp;#39;s important to note that GitHub Actions has a repository-wide cache size limit, which can be a consideration for very large monorepos.&lt;/p&gt;
&lt;p&gt;GitLab CI provides caching functionality that is configured directly within the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file using the &lt;code&gt;cache&lt;/code&gt; keyword. It supports various caching strategies, including branch-based caching (where the cache is specific to a branch), job-based caching (specific to a job), and content-based caching, which uses the checksum of files like dependency lock files to determine when the cache should be invalidated. GitLab CI also offers fallback cache keys, allowing jobs to attempt to retrieve a more general cache if a specific one is not found. Additionally, GitLab CI supports distributed caching, where the cache is stored in external storage like S3 buckets, making it accessible to multiple runners, which is particularly advantageous for scalable monorepo builds.&lt;/p&gt;
&lt;p&gt;Both platforms offer comprehensive caching mechanisms designed to significantly reduce build times in monorepos by reusing previously downloaded dependencies and built artifacts. GitHub Actions provides a specific action and supports remote caching, while GitLab CI integrates caching configuration directly into its YAML with advanced features like content-based caching and distributed storage.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Effectiveness in Monorepos&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For GitHub Actions to effectively cache dependencies and outputs in a monorepo, it requires careful definition of cache keys and paths within the cache action. The cache key should ideally include information that distinguishes the dependencies and outputs of different projects within the monorepo, such as the path to the project&amp;#39;s dependency lock file. Remote caching solutions can be especially beneficial for monorepos managed with tools like Turborepo, as they allow for efficient sharing of cached artifacts across the entire monorepo and potentially across multiple repositories. However, the 10GB cache limit per repository might necessitate more strategic caching configurations or the use of remote caching for very large projects.&lt;/p&gt;
&lt;p&gt;GitLab CI emphasizes the importance of defining granular cache keys and paths that are specific to the individual projects or components within the monorepo. Content-based caching, where the cache key is derived from the content of dependency lock files (e.g., &lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;pom.xml&lt;/code&gt;), is particularly effective for monorepos as it ensures that the cache is only invalidated when the dependencies for a specific project actually change. This prevents unnecessary cache invalidations when other parts of the monorepo are modified. Distributed caching in GitLab CI is also highly beneficial for monorepos with multiple runners or autoscaling runners, as it ensures that the cache is readily available to any runner that picks up a job, regardless of which runner initially created the cache.&lt;/p&gt;
&lt;p&gt;Effective caching in monorepos on both platforms hinges on properly configuring cache keys and paths to target specific projects and their dependencies. GitLab CI&amp;#39;s content-based caching and distributed caching offer significant advantages for large, multi-project monorepos in terms of optimizing cache efficiency and availability. GitHub Actions users might need to leverage remote caching solutions for very large projects to overcome the built-in size limitations.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Common Issues&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Users of GitHub Actions might encounter challenges with the 10GB cache size limit, especially in very large monorepos, which can lead to frequent cache misses and longer build times.&lt;/p&gt;
&lt;p&gt;In GitLab CI, a common issue is that the cache, by default, might be local to the specific runner that created it. This can result in cache misses when subsequent jobs are executed on different runners, unless distributed caching is explicitly configured. Additionally, users have reported unexpected cache behavior when using local includes in the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file, which can sometimes lead to caching not working as expected.&lt;/p&gt;
&lt;p&gt;These common issues highlight the importance of understanding the nuances of the caching mechanisms on each platform and configuring them appropriately for the specific needs of the monorepo. GitHub Actions users should be mindful of the size limit and might need to explore remote caching for large projects. GitLab CI users should ensure that distributed caching is enabled for consistent cache access across their runner infrastructure.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Secure Secrets: How Do GitHub Actions and GitLab CI Manage Sensitive Information Within a Monorepo?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Managing sensitive information, such as API tokens, database credentials, and private keys, securely within CI/CD pipelines is paramount. Both GitHub Actions and GitLab CI offer mechanisms for handling secrets in a monorepo environment.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Secrets Management Capabilities&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitHub Actions provides a secure way to store sensitive information as secrets at the repository, environment, and organization levels. Repository secrets are specific to a single repository, while environment secrets are scoped to a particular environment (e.g., production, staging). Organization-level secrets can be configured with access policies to control which repositories within an organization can access them. Secrets are accessed within workflow files using the &lt;code&gt;secrets&lt;/code&gt; context and are automatically redacted from workflow logs to prevent accidental exposure. GitHub Actions also supports integration with external secret management tools and offers OpenID Connect (OIDC) for securely authenticating with cloud providers without the need to store long-lived credentials.&lt;/p&gt;
&lt;p&gt;GitLab CI offers CI/CD variables, which can be marked as &amp;quot;masked&amp;quot; to hide their values in job logs, as a basic way to handle secrets. However, for more robust security, GitLab CI strongly recommends and provides integration with dedicated external secret management providers such as HashiCorp Vault, Google Cloud Secret Manager, and Azure Key Vault. These integrations allow teams to securely store and retrieve secrets from these external systems within their CI/CD pipelines. GitLab CI also supports ID token authentication, enabling secure access to cloud resources like AWS Secret Manager without needing to store API keys as CI/CD variables.&lt;/p&gt;
&lt;p&gt;Both platforms provide secure ways to manage sensitive information required by CI/CD pipelines. GitHub Actions offers a built-in, tiered system for managing secrets directly within the platform, while GitLab CI emphasizes integration with specialized external secret management solutions for enhanced security and control.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Monorepo Considerations&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;When managing a monorepo with GitHub Actions, organization-level secrets with carefully defined repository access policies can be particularly beneficial for handling secrets that are shared across multiple projects within the repository. This provides a centralized way to manage common credentials. For project-specific secrets, such as API tokens for individual services, repository secrets can be used. Additionally, for integrations with tools like SonarQube, project-level tokens can be securely stored as repository secrets within the monorepo.&lt;/p&gt;
&lt;p&gt;In GitLab CI, the integration with external secret managers allows for fine-grained control over secret access based on the specific project or application being built or deployed within the monorepo. Depending on the capabilities of the chosen secret management provider, teams can scope access to secrets based on various criteria. While CI/CD variables can be defined at the project or group level in GitLab CI, using external secret management solutions is the recommended best practice for handling sensitive information in a monorepo environment.&lt;/p&gt;
&lt;p&gt;Managing secrets effectively in a monorepo requires careful consideration of the scope and access control. GitHub Actions&amp;#39; organization-level secrets offer a convenient way to manage shared credentials, while GitLab CI&amp;#39;s integration with external providers allows for more granular, provider-specific access management within the monorepo.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Best Practices&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For GitHub Actions, best practices include always storing sensitive information as GitHub secrets and avoiding the practice of hardcoding credentials directly in workflow files. Utilizing environment secrets helps to scope credentials to specific deployment environments, enhancing security. Leveraging OIDC for cloud provider authentication is also recommended to minimize the need for managing long-lived secrets.&lt;/p&gt;
&lt;p&gt;In GitLab CI, the prevailing best practice is to prioritize the use of external secret management providers over CI/CD variables for storing sensitive data within a monorepo. Teams should apply the principle of least privilege, granting only the necessary access to secrets. Regularly auditing the usage of secrets and considering features like secret rotation offered by external providers can further enhance security.&lt;/p&gt;
&lt;p&gt;Overall, best practices for secrets management in monorepos on both platforms emphasize the importance of secure storage, scoped access, and avoiding the direct embedding of sensitive information in CI/CD configurations. GitLab CI&amp;#39;s strong emphasis on integrating with dedicated external secret management tools aligns with industry best practices for handling sensitive information in enterprise environments, especially those managing large and complex monorepos.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Troubleshooting Tips: What Common Challenges Arise and How Can They Be Solved When Using These Platforms with Monorepos?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Managing CI/CD for monorepos can present unique challenges. Understanding common issues and their solutions for both GitHub Actions and GitLab CI is crucial for a smooth development process.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Common Challenges&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;GitHub Actions users working with large monorepos might encounter limitations with the 10GB cache size, which can lead to slower build times due to frequent cache misses. Heavily used monorepos with a high volume of jobs and pull requests can also face issues with reaching API call limits, potentially disrupting workflows. Some users find the inability to re-run a single failed job in certain scenarios to be inefficient. Additionally, managing and maintaining very long and complex YAML workflow files, which can be common in large monorepos, can become a significant challenge.&lt;/p&gt;
&lt;p&gt;GitLab CI users might experience performance degradation with extremely large monorepos due to the time required for Git operations like cloning and fetching, especially with frequent CI/CD runs. The &lt;code&gt;rules:changes&lt;/code&gt; feature, while powerful for targeted execution, can sometimes lead to unexpected pipeline triggers if not configured with precision. Caching in GitLab CI can be limited to the specific runner that created it unless distributed caching is explicitly configured, potentially leading to cache misses. Dynamically generating complex CI/CD pipelines for monorepos, while offering flexibility, can also introduce challenges in terms of debugging and maintenance.&lt;/p&gt;
&lt;p&gt;These challenges highlight the complexities of managing CI/CD for monorepos at scale on both platforms. Recognizing these potential pitfalls allows teams to proactively seek solutions and optimize their configurations.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Solutions and Workarounds&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To address the 10GB cache limit in GitHub Actions, teams can explore using remote caching solutions like Vercel Remote Cache or implement custom caching strategies to store artifacts outside of the default cache. To mitigate issues with API call limits, it&amp;#39;s important to optimize workflows and potentially implement custom checks to prevent merging of pull requests if critical jobs are canceled due to these limits. While directly re-running a single job isn&amp;#39;t always available, workflows can often be configured to retry failed jobs automatically. For managing complex YAML workflows, breaking them down into smaller, reusable workflows using features like composite actions can significantly improve maintainability.&lt;/p&gt;
&lt;p&gt;In GitLab CI, employing shallow cloning (&lt;code&gt;git clone --depth&lt;/code&gt;) and using &lt;code&gt;git fetch&lt;/code&gt; instead of full clones can help reduce the time taken for Git operations on large monorepos. To avoid unexpected pipeline triggers with &lt;code&gt;rules:changes&lt;/code&gt;, it&amp;#39;s recommended to create feature branches and open merge requests to observe the behavior before merging to the main branch. Configuring distributed caching using external object storage like S3 ensures that the cache is accessible across all runners, improving efficiency. For managing the complexity of dynamically generated pipelines, leveraging features like parent-child pipelines and pipeline templates can provide better structure and organization.&lt;/p&gt;
&lt;p&gt;By understanding and implementing these solutions and workarounds, teams can effectively mitigate the common challenges associated with using GitHub Actions and GitLab CI for monorepo management, leading to more efficient and stable CI/CD pipelines.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Answering Your Queries: Frequently Asked Questions About GitHub Actions vs. GitLab CI for Monorepos.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Here are some frequently asked questions regarding the use of GitHub Actions and GitLab CI for managing monorepos:&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Which platform is generally considered easier to set up and use for a monorepo?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Both platforms have their learning curves. GitHub Actions might be perceived
  as slightly more approachable initially due to its modular workflow structure
  and the visual representation of workflows. However, GitLab CI&amp;#39;s single
  &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file can offer a more centralized view. The ease of use often
  depends on the team&amp;#39;s prior experience with either platform and the complexity
  of the monorepo&amp;#39;s CI/CD requirements.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do the pricing models of GitHub Actions and GitLab CI compare for monorepo CI/CD, especially for large teams and high usage?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Both platforms offer free tiers with limitations, and paid plans with varying
  features and usage allowances. GitHub Actions charges based on per-minute
  usage, with different rates for different operating systems, and also offers
  fixed-price plans with included minutes and storage. GitLab CI offers paid
  plans with a fixed cost per user and includes a certain number of CI/CD
  minutes per month, with options to purchase additional minutes or storage. The
  best choice in terms of cost depends on factors like the frequency and
  duration of builds, the number of team members, and the specific requirements
  for runners and storage.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Which platform tends to offer better performance for very large monorepos in terms of Git operations and CI/CD execution speed?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Experiences vary, but some users have reported that GitHub offers improved
  performance for monorepos, particularly in terms of Git push/pull and CI job
  start times. However, GitLab has also made significant improvements in
  handling large repositories, and performance can depend heavily on repository
  optimization and pipeline configuration on both platforms.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How well do GitHub Actions and GitLab CI handle dependencies between different projects or services within a monorepo?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Both platforms provide mechanisms to manage dependencies. GitHub Actions
  allows for defining workflows that trigger based on changes in specific paths,
  which can be used to trigger builds for dependent projects when a library or
  shared component is updated. GitLab CI&amp;#39;s parent-child pipelines and
  conditional includes based on changed paths also enable the triggering of
  pipelines for dependent projects.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are some key strategies for optimizing build times in a monorepo using caching on each platform?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  For GitHub Actions, key strategies include carefully defining cache keys that
  include dependency file hashes and using the &lt;code&gt;cache&lt;/code&gt; action to store and
  restore dependencies and build outputs for specific projects within the
  monorepo. Leveraging remote caching solutions can also be beneficial. For
  GitLab CI, using content-based caching with dependency lock files as part of
  the cache key ensures that the cache is only invalidated when dependencies
  change. Configuring distributed caching is also crucial for sharing the cache
  across multiple runners.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do the communities and documentation compare for users specifically looking to manage monorepos with these platforms?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Both GitHub and GitLab have large and active communities and extensive
  documentation. GitHub&amp;#39;s community is vast and highly engaged, with a wealth of
  community-contributed actions and resources available. GitLab also has a
  strong community and provides comprehensive documentation, including specific
  sections on managing monorepos with GitLab CI/CD.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;For organizations already heavily invested in either the GitHub or GitLab ecosystem, what are the key advantages of using their respective CI/CD solutions for monorepos?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  For organizations deeply embedded in the GitHub ecosystem, using GitHub
  Actions offers seamless integration with their code hosting and collaboration
  workflows. The extensive Marketplace provides easy access to a wide range of
  integrations. For organizations heavily invested in GitLab, using GitLab CI
  offers tight integration with all other GitLab features, providing a unified
  DevOps platform experience.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Real-World Insights: What Do Case Studies and User Experiences Reveal About Using These Tools for Monorepos?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Real-world experiences offer valuable perspectives on the practical application of GitHub Actions and GitLab CI for monorepo management. Clear Street&amp;#39;s migration from GitLab CI to GitHub Actions highlighted improved monorepo performance and a more user-friendly UI. Their experience underscores the importance of performance, especially Git operation speed, when dealing with large monorepos.&lt;/p&gt;
&lt;p&gt;A team using GitHub Actions with Java and Maven in a monorepo found that leveraging path-based workflows was crucial for ensuring that only the necessary parts of the project were built and tested upon code changes. This case study emphasizes the efficiency gains achievable through targeted workflow execution.&lt;/p&gt;
&lt;p&gt;Examples of setting up CI pipelines for Python monorepos with GitHub Actions demonstrate the use of reusable workflows and careful configuration of change detection to manage the complexity of multi-package repositories. These examples highlight the importance of modularity and automation in maintaining scalable CI/CD for monorepos.&lt;/p&gt;
&lt;p&gt;GitLab&amp;#39;s Directed Acyclic Graph (DAG) feature has been successfully used to build efficient CI/CD pipelines for monorepos with decoupled components, allowing for independent and parallel execution of pipelines for different parts of the repository. This illustrates GitLab&amp;#39;s capability to handle complex monorepo structures.&lt;/p&gt;
&lt;p&gt;However, not all experiences are uniformly positive. One user shared challenges faced with GitHub Actions in a large monorepo, particularly concerning the 10GB cache limit and reaching API limits under heavy load. This highlights potential limitations of GitHub Actions at extreme scale.&lt;/p&gt;
&lt;p&gt;Anecdotal evidence and opinions shared on platforms like Reddit and Hacker News reveal a range of experiences, with some users preferring GitHub Actions for its flexibility and ecosystem, while others favor GitLab CI for its integrated platform approach and advanced features. These discussions underscore that the &amp;quot;best&amp;quot; platform often depends on the specific context and priorities of the team.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Pros and Cons Analysis: What Are the Key Strengths and Weaknesses of Each Platform for Monorepo Management?&lt;/strong&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;GitLab CI&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Extensive Marketplace, broader OS support, flexible workflow definition, organization-level secrets&lt;/td&gt;
&lt;td&gt;Tight GitLab integration, powerful &lt;code&gt;include&lt;/code&gt; with &lt;code&gt;rules:changes&lt;/code&gt;, parent-child pipelines, content-based and distributed caching, robust external secrets management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited cache size, potential API call limits, complex YAML for large workflows, less straightforward single job re-run&lt;/td&gt;
&lt;td&gt;Primarily Linux runners (macOS/Windows beta), UI less intuitive for some, potential Git performance issues for very large repos&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Making the Right Choice: Which Platform Might Be the Best Fit for Different Monorepo Scenarios?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The optimal CI/CD platform for a monorepo is not a one-size-fits-all decision. Organizations already heavily invested in the GitHub ecosystem and requiring a wide array of integrations from the Marketplace might find GitHub Actions to be a natural fit. The broader operating system support can also be a key advantage for monorepos with diverse platform requirements.&lt;/p&gt;
&lt;p&gt;Teams that prioritize tight integration within the GitLab platform, along with advanced caching and secrets management features, might find GitLab CI more suitable. The &lt;code&gt;include&lt;/code&gt; with &lt;code&gt;rules:changes&lt;/code&gt; feature is particularly powerful for managing pipelines in monorepos.&lt;/p&gt;
&lt;p&gt;Extremely large monorepos should carefully consider the 10GB cache limit in GitHub Actions and the potential Git performance considerations in GitLab CI. In such cases, exploring remote caching solutions with GitHub Actions or optimizing Git operations and utilizing distributed caching with GitLab CI might be necessary.&lt;/p&gt;
&lt;p&gt;Organizations looking for a simpler initial setup and a more visually oriented workflow definition might lean towards GitHub Actions, while those needing more fine-grained control over complex pipeline logic might prefer the flexibility offered by GitLab CI. Ultimately, cost considerations, team familiarity, and specific project requirements will play a significant role in the final decision.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion: Selecting the Ideal CI/CD Solution for Your Monorepo.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Choosing the right CI/CD platform for a monorepo is a critical decision that can significantly impact development efficiency and software quality. Both GitHub Actions and GitLab CI offer a comprehensive set of features and capabilities tailored to handle the complexities of monorepo management. GitHub Actions shines with its extensive marketplace and broader OS support, while GitLab CI offers tight integration with its platform and advanced features like conditional includes and content-based caching.&lt;/p&gt;
&lt;p&gt;The decision ultimately hinges on a thorough evaluation of the specific needs of your monorepo, your team&amp;#39;s expertise and preferences, and your organization&amp;#39;s existing infrastructure. We encourage you to conduct your own proof-of-concept evaluations to determine which platform best aligns with your unique context and will empower your team to effectively manage your monorepo.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Monorepo CI best practices - Buildkite, accessed on April 8, 2025, &lt;a href=&quot;https://buildkite.com/resources/blog/monorepo-ci-best-practices/&quot;&gt;https://buildkite.com/resources/blog/monorepo-ci-best-practices/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Monorepo with Java, Maven and GitHub Actions, including basic example - DEV Community, accessed on April 8, 2025, &lt;a href=&quot;https://dev.to/kgunnerud/our-experience-monorepo-with-java-maven-and-github-actions-2aho&quot;&gt;https://dev.to/kgunnerud/our-experience-monorepo-with-java-maven-and-github-actions-2aho&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitLab CI/CD vs. GitHub Actions - Graphite, accessed on April 8, 2025, &lt;a href=&quot;https://graphite.dev/guides/gitlab-cicd--vs-github-actions&quot;&gt;https://graphite.dev/guides/gitlab-cicd--vs-github-actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Building a GitLab CI/CD pipeline for a monorepo the easy way, accessed on April 8, 2025, &lt;a href=&quot;https://about.gitlab.com/blog/2024/07/30/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way/&quot;&gt;https://about.gitlab.com/blog/2024/07/30/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Control the concurrency of workflows and jobs - GitHub Docs, accessed on April 8, 2025, &lt;a href=&quot;https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs&quot;&gt;https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Creating separate monorepo CI/CD pipelines with GitHub Actions ..., accessed on April 8, 2025, &lt;a href=&quot;https://blog.logrocket.com/creating-separate-monorepo-ci-cd-pipelines-github-actions/&quot;&gt;https://blog.logrocket.com/creating-separate-monorepo-ci-cd-pipelines-github-actions/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Managing monorepos - GitLab Docs, accessed on April 8, 2025, &lt;a href=&quot;https://docs.gitlab.com/user/project/repository/monorepos/&quot;&gt;https://docs.gitlab.com/user/project/repository/monorepos/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Caching dependencies to speed up workflows - GitHub Docs, accessed on April 8, 2025, &lt;a href=&quot;https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows&quot;&gt;https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub Actions | Turborepo, accessed on April 8, 2025, &lt;a href=&quot;https://turbo.build/docs/guides/ci-vendors/github-actions&quot;&gt;https://turbo.build/docs/guides/ci-vendors/github-actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Caching in GitLab CI/CD | GitLab Docs, accessed on April 8, 2025, &lt;a href=&quot;https://docs.gitlab.com/ci/caching/&quot;&gt;https://docs.gitlab.com/ci/caching/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using external secrets in CI | GitLab Docs, accessed on April 8, 2025, &lt;a href=&quot;https://docs.gitlab.com/ci/secrets/&quot;&gt;https://docs.gitlab.com/ci/secrets/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to implement secret management best practices with GitLab, accessed on April 8, 2025, &lt;a href=&quot;https://about.gitlab.com/the-source/security/how-to-implement-secret-management-best-practices-with-gitlab/&quot;&gt;https://about.gitlab.com/the-source/security/how-to-implement-secret-management-best-practices-with-gitlab/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>CI/CD</category><category>Monorepos</category><category>Software Development</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0075-github-actions-vs-gitlab-ci-for-monorepos/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Full-Stack Observability with OpenTelemetry: Getting a Clear View of Your Systems</title><link>https://mkabumattar.com/blog/post/full-stack-observability-opentelemetry/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/full-stack-observability-opentelemetry/</guid><description>Learn how to get a full view of your complex systems using OpenTelemetry. This guide covers the basics, benefits, using it with Prometheus and Grafana, and answers common questions.</description><pubDate>Sat, 19 Apr 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Think about how complicated software can be these days. You&amp;#39;ve got all these different parts talking to each other – the stuff you see on the screen, the behind-the-scenes processing, the databases, and all the computers that make it run. When something goes wrong in this big mess, figuring out what caused it can feel like trying to find a needle in a haystack. Teams often end up using a bunch of different monitoring tools, and each one only shows a small piece of the puzzle. This makes fixing problems take way too long, which is frustrating for everyone and can really mess with the user experience.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s where full-stack observability comes in as a really helpful solution. It gives you a complete understanding of everything that&amp;#39;s going on in your application, so you can handle the complexity and fix issues much faster and easier. And guess what? OpenTelemetry is this cool, open way to collect all the information you need to get this full picture.&lt;/p&gt;
&lt;h2&gt;So, What&amp;#39;s the Deal with Full-Stack Observability?&lt;/h2&gt;
&lt;p&gt;Basically, full-stack observability is about keeping a close eye on everything in your application, from when a user interacts with it on their phone or computer, all the way down to the nuts and bolts of the computers it runs on. It&amp;#39;s like having a bird&amp;#39;s-eye view of your applications, whether they&amp;#39;re living in the cloud, on your own servers, or even in those fancy Kubernetes setups. But it&amp;#39;s not just about gathering data; the real magic is in getting useful insights that show you how all the different parts of your system connect and affect each other. It helps you really understand how things work together.&lt;/p&gt;
&lt;p&gt;To get this full view, you need to collect and look at three main types of information, often called the three pillars of observability. &lt;strong&gt;Metrics&lt;/strong&gt; are like taking measurements of how your system is doing over time, like how much of your computer&amp;#39;s brainpower (CPU) it&amp;#39;s using, how much memory it&amp;#39;s taking up, how long it takes for requests to go through, and how many errors are happening. These numbers help you see the overall health and resource usage of your system. &lt;strong&gt;Logs&lt;/strong&gt; are like detailed diaries of everything that&amp;#39;s happening inside, with timestamps to show when things occurred. They give you the story of what happened at a specific moment. And then there are &lt;strong&gt;traces&lt;/strong&gt;, which show you the whole journey of a request as it travels through all the different services in your system. This is super important these days because applications are often made up of lots of little services that talk to each other. Traces help you find bottlenecks and see the exact steps involved in fulfilling a user&amp;#39;s request.&lt;/p&gt;
&lt;p&gt;Why bother with full-stack observability? Well, it&amp;#39;s got some pretty awesome benefits. You can spot and fix problems way faster because you can see how different parts of your system are interacting, which means less downtime. This complete view also helps you find those slow spots in your system and make things run smoother and more efficiently, leading to happier users. By catching potential problems early, you can keep your applications stable and reliable. Plus, when everyone – developers, operations folks, and security teams – can see the same picture, it makes communication and teamwork much better. And let&amp;#39;s not forget that by finding and fixing inefficiencies, you can actually save money on your operations.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s a big difference between old-school monitoring and full-stack observability. Traditional monitoring often focuses on just tracking certain things you already know about and setting up alerts for when those things go wrong. Observability, on the other hand, lets you ask and answer questions about what&amp;#39;s going on inside your system, even questions you didn&amp;#39;t think to ask beforehand. It lets you really dig into how your system behaves based on all the data you&amp;#39;re collecting. Also, to get true full-stack observability, you can&amp;#39;t just collect data in separate silos. You need to actively connect and analyze information from every part of your technology setup to get meaningful insights. By putting together the pieces of the puzzle from different areas, you can get a clear understanding of your overall performance and health, which helps you solve problems faster and more effectively.&lt;/p&gt;
&lt;h2&gt;What&amp;#39;s OpenTelemetry and Why Should You Care?&lt;/h2&gt;
&lt;p&gt;OpenTelemetry, or OTel as it&amp;#39;s often called, is like this open-source project under the Cloud Native Computing Foundation (CNCF). It gives you a whole toolkit of things like instructions (APIs), ready-to-use code (SDKs), and tools to help you create, collect, and send out all that telemetry data – traces, metrics, and logs – from your applications and the computers they run on. In today&amp;#39;s world where &lt;strong&gt;distributed systems&lt;/strong&gt; are everywhere, OpenTelemetry is super important because it gives you a standard, neutral way to collect this data. This makes it much simpler to see how requests move through all those interconnected services, giving you the end-to-end visibility you need to fix problems and make things run better. By showing you how your application is behaving while it&amp;#39;s running, OpenTelemetry helps developers and operations teams find slowdowns and figure out where errors are coming from more easily.&lt;/p&gt;
&lt;p&gt;The OpenTelemetry project has a few key parts. It has specific instructions and code libraries for different programming languages (like Java, Python, and Go) that developers can use to make their code produce telemetry data. Then there&amp;#39;s the &lt;strong&gt;OpenTelemetry Protocol (OTLP)&lt;/strong&gt;, which is like a universal language for sending telemetry data efficiently between different parts of your system, no matter which company made them. It often uses things like gRPC or HTTP to do this. The &lt;strong&gt;Collector&lt;/strong&gt; is like a central hub that can receive telemetry data from all sorts of places, process it if needed (like combining it, filtering it, or adding more information), and then send it off to one or more places where you can actually look at it. This central piece can also handle things like removing sensitive information and grouping data together to make sending it more efficient. Plus, there&amp;#39;s &lt;strong&gt;automatic instrumentation&lt;/strong&gt;, which is really cool because it lets you collect telemetry data from common software without having to change your code much, making the whole process much easier.&lt;/p&gt;
&lt;p&gt;There are some really good reasons why companies should think about using OpenTelemetry. Because it&amp;#39;s neutral, you&amp;#39;re not stuck with a specific monitoring company, giving you the freedom to choose the tools that work best for you, whether they&amp;#39;re free and open-source or you pay for them. This also means you&amp;#39;re not locked into one vendor. The fact that it standardizes all types of telemetry data makes setting things up and managing the data much simpler. Since it&amp;#39;s a project under the CNCF, OpenTelemetry has a big and active community of people working on it, which means it&amp;#39;s constantly being improved, it&amp;#39;s stable, and it&amp;#39;s likely to stick around for the long haul. It&amp;#39;s also designed to be flexible, so you can add support for your own custom data sources and backend systems. Ultimately, by giving you a consistent and complete way to collect telemetry data, OpenTelemetry makes it much easier for your organization to see what&amp;#39;s going on in your systems and get really useful insights.&lt;/p&gt;
&lt;p&gt;OpenTelemetry came about because two earlier CNCF projects, OpenTracing and OpenCensus, joined forces. This shows that the industry realized how important it was to have a standard way of doing observability. Instead of having competing standards, they combined their efforts to create a stronger and more widely used framework. It&amp;#39;s important to remember that OpenTelemetry itself doesn&amp;#39;t store or show you the telemetry data. Its main job is to handle the initial steps of collecting and sending out that data. This separation gives you the advantage of picking the storage and analysis tools that best fit your needs and your current setup.&lt;/p&gt;
&lt;h2&gt;How Does OpenTelemetry Make Our Monitoring Better?&lt;/h2&gt;
&lt;p&gt;OpenTelemetry really steps up our monitoring game by giving us a standard way to collect metrics, logs, and traces from all sorts of different applications and services. This gets rid of the inconsistencies you often see when you&amp;#39;re using different tools or special agents for different parts of your system. This standardization even applies to how the telemetry data is named and formatted.&lt;/p&gt;
&lt;p&gt;One of the big wins with OpenTelemetry is that it doesn&amp;#39;t tie you to a specific vendor. You&amp;#39;re no longer stuck with the special agents and data formats of one particular monitoring company. This freedom lets you choose the monitoring and observability tools that make the most sense for your unique situation, and you can even switch providers later on without having to completely redo your setup.&lt;/p&gt;
&lt;p&gt;OpenTelemetry also makes it much easier to understand the context and connections between different pieces of telemetry data. By having a single framework for collecting traces, logs, and metrics, it helps you see how these different types of data relate to each other. This complete picture of how your system is behaving makes it much simpler to figure out the root cause of problems. Especially in &lt;strong&gt;distributed systems&lt;/strong&gt;, OpenTelemetry&amp;#39;s context propagation makes sure that important information, like trace IDs, travels along with requests as they hop between services.&lt;/p&gt;
&lt;p&gt;Setting up the instrumentation is also easier with OpenTelemetry. It offers automatic instrumentation for many popular software libraries and frameworks, which means you can collect telemetry data with much less manual coding. This saves developers time and lets them focus on building new features instead of getting bogged down in monitoring setup.&lt;/p&gt;
&lt;p&gt;Furthermore, OpenTelemetry improves how different systems and platforms work together. Its standard protocols and data formats, including those APIs and SDKs, make it easy to share and analyze data across your entire infrastructure. This unified approach fills in the gaps in visibility in &lt;strong&gt;distributed systems&lt;/strong&gt; by providing a common way to instrument all your services. This means you don&amp;#39;t have to re-instrument your code or install different special agents if you decide to change your backend platform.&lt;/p&gt;
&lt;p&gt;Finally, because it&amp;#39;s a Cloud Native Computing Foundation project with a lively and active community, OpenTelemetry is designed to last. It&amp;#39;s constantly being updated and adapting to new technologies, making sure your observability setup stays relevant and effective over time, unlike those proprietary solutions that rely on vendors to build new integrations for everything. This commitment to standardization and vendor neutrality can also save organizations money by letting them use fewer monitoring tools and avoid the costs associated with proprietary solutions.&lt;/p&gt;
&lt;h2&gt;OpenTelemetry vs. Traditional Monitoring: What&amp;#39;s the Real Difference?&lt;/h2&gt;
&lt;p&gt;Traditional monitoring often focuses on specific parts of a system, like individual servers or application logs, which can give you a somewhat limited view of how everything is working together. It usually answers the question of &amp;quot;what&amp;quot; is happening in the system based on predefined metrics and alerts. A key thing about traditional monitoring tools is that they often use their own special agents and data formats, which can lock you into using that vendor.&lt;/p&gt;
&lt;p&gt;OpenTelemetry, on the other hand, takes a much broader approach. It looks beyond just individual parts and emphasizes connecting the dots between telemetry data from the entire application stack to give you a much more complete understanding of how the system is behaving. This helps teams figure out the &amp;quot;why&amp;quot; behind system events and performance issues. As an open-source and vendor-neutral framework, OpenTelemetry offers a lot of flexibility and makes it easier for different systems and tools to work together. It collects not just metrics and logs, but also traces, in a standard way, which makes it much easier to connect these different types of data and get deeper insights into how your system is working.&lt;/p&gt;
&lt;p&gt;When you think about how OpenTelemetry relates to traditional Application Performance Monitoring (APM) tools like &lt;strong&gt;New Relic&lt;/strong&gt;, it&amp;#39;s important to understand what each one does. &lt;strong&gt;New Relic&lt;/strong&gt; is a comprehensive, commercial platform that gives you end-to-end monitoring capabilities, with a strong focus on APM. In the past, it has relied on its own special agents to collect telemetry data. However, recognizing how important and widely used OpenTelemetry is becoming, &lt;strong&gt;New Relic&lt;/strong&gt; now supports taking in telemetry data in the OpenTelemetry format (OTLP). This means that if you&amp;#39;ve set up your applications with OpenTelemetry, you can easily send your telemetry data to &lt;strong&gt;New Relic&lt;/strong&gt; for more advanced analysis and visualization.&lt;/p&gt;
&lt;p&gt;Using OpenTelemetry together with &lt;strong&gt;New Relic&lt;/strong&gt; can be a really powerful combination. You get the flexibility and standardization of OpenTelemetry for collecting data, along with the strong analytics and visualization features of &lt;strong&gt;New Relic&lt;/strong&gt;. OpenTelemetry can be especially useful for getting instrumentation in places where it might not be easy to deploy &lt;strong&gt;New Relic&lt;/strong&gt;&amp;#39;s own agents. It&amp;#39;s worth noting, though, that while &lt;strong&gt;New Relic&lt;/strong&gt; supports OpenTelemetry, some features might not work exactly the same as they do with &lt;strong&gt;New Relic&lt;/strong&gt;&amp;#39;s own agents, and the way the data is structured might not always line up perfectly. Still, &lt;strong&gt;New Relic&lt;/strong&gt; and other companies are increasingly embracing OpenTelemetry by supporting OTLP and actively contributing to the OpenTelemetry project. This shows a clear trend towards OpenTelemetry becoming a fundamental standard in the world of observability.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Traditional Monitoring&lt;/th&gt;
&lt;th&gt;OpenTelemetry&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Focuses on specific parts, often isolated views&lt;/td&gt;
&lt;td&gt;Covers the whole stack, connects data across everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Question Answered&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;What went wrong?&lt;/td&gt;
&lt;td&gt;Why did it go wrong?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vendor Lock-in&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usually high&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Types&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mostly metrics and logs&lt;/td&gt;
&lt;td&gt;Metrics, logs, and traces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instrumentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Often needs vendor-specific agents&lt;/td&gt;
&lt;td&gt;Standard APIs/SDKs, automatic setup available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can be expensive, especially with proprietary tools&lt;/td&gt;
&lt;td&gt;Open-source framework, backend costs might apply&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;While traditional APM tools like &lt;strong&gt;New Relic&lt;/strong&gt; give you a smooth, ready-to-go experience, OpenTelemetry offers a more customizable way to set things up, which is really helpful for complex, cloud-based environments. Many organizations are now choosing to use both, with OpenTelemetry for collecting data and traditional APM tools for showing and analyzing it. Also, while traditional monitoring tools often have built-in ways to analyze data and detect problems, OpenTelemetry needs to be connected to separate backend tools for these things, giving you more choice in which analysis platform you want to use.&lt;/p&gt;
&lt;h2&gt;Getting Your Hands Dirty: OpenTelemetry in Action with Open Source Tools.&lt;/h2&gt;
&lt;p&gt;The real power of OpenTelemetry shines when you use it with other open-source tools in the observability world. &lt;strong&gt;Prometheus&lt;/strong&gt; and &lt;strong&gt;Grafana&lt;/strong&gt; are two such tools that, when you put them together with OpenTelemetry, create a strong and flexible observability solution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Metrics with Prometheus: A Powerful Combination.&lt;/strong&gt; &lt;strong&gt;Prometheus&lt;/strong&gt; is a really popular open-source toolkit for monitoring and alerting, and it&amp;#39;s known for being great at collecting and storing metrics as time-series data. It works by periodically asking applications or special exporters for their metrics. OpenTelemetry can easily work with &lt;strong&gt;Prometheus&lt;/strong&gt; by sending the metrics it collects in the format that &lt;strong&gt;Prometheus&lt;/strong&gt; understands. You can do this using the &lt;strong&gt;Prometheus&lt;/strong&gt; exporter that&amp;#39;s part of the OpenTelemetry Collector. The Collector acts like a middleman, getting metrics from applications that are set up with OpenTelemetry using the OTLP protocol, and then changing them into a format that &lt;strong&gt;Prometheus&lt;/strong&gt; can easily use. Another cool thing is that &lt;strong&gt;Prometheus&lt;/strong&gt; can now directly take in OpenTelemetry metrics using its OTLP receiver, which makes things even simpler.&lt;/p&gt;
&lt;p&gt;To give you an idea of how this works, you&amp;#39;d usually set up the OpenTelemetry SDK in your application to send the metrics it collects to the OpenTelemetry Collector using OTLP. Then, you&amp;#39;d configure the Collector to use the &lt;strong&gt;Prometheus&lt;/strong&gt; exporter, telling it the network address (like a website address and port number) where &lt;strong&gt;Prometheus&lt;/strong&gt; can come and get the metrics. Finally, in the &lt;strong&gt;Prometheus&lt;/strong&gt; settings, you&amp;#39;d define a job that tells it to go to that address on the OpenTelemetry Collector. This setup gives you the big advantage of being able to use &lt;strong&gt;Prometheus&lt;/strong&gt;&amp;#39;s powerful query language, PromQL, and its smart alerting rules with the standardized and complete metrics that OpenTelemetry gathers. It&amp;#39;s good to know that the way OpenTelemetry and &lt;strong&gt;Prometheus&lt;/strong&gt; name metrics might be a little different. However, the OpenTelemetry Collector often has ways to handle these differences and make the metric names consistent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Visualizing Your Data with Grafana.&lt;/strong&gt; &lt;strong&gt;Grafana&lt;/strong&gt; is another really popular open-source platform that&amp;#39;s all about showing data in a visual way and monitoring things. It can work with lots of different data sources, and &lt;strong&gt;Prometheus&lt;/strong&gt; is a very common one. &lt;strong&gt;Grafana&lt;/strong&gt; lets you create really customizable and interactive dashboards to see your monitoring data. Once your OpenTelemetry metrics are stored in &lt;strong&gt;Prometheus&lt;/strong&gt; (or your traces are in a backend like Jaeger or Tempo, and your logs are in Loki), you can set up &lt;strong&gt;Grafana&lt;/strong&gt; to connect to these places. By adding &lt;strong&gt;Prometheus&lt;/strong&gt; (or the right backend) as a data source in &lt;strong&gt;Grafana&lt;/strong&gt;, you can then build dashboards to effectively visualize your OpenTelemetry data.&lt;/p&gt;
&lt;p&gt;For metrics, &lt;strong&gt;Grafana&lt;/strong&gt; lets you create different kinds of charts, like time-series charts to see how things like CPU usage or memory consumption change over time, heatmaps to analyze how long requests are taking, and histograms to understand the distribution of response times. If you&amp;#39;re using a tracing backend like Jaeger or Grafana Tempo with OpenTelemetry, &lt;strong&gt;Grafana&lt;/strong&gt; can show you the flow of individual requests as they go through a &lt;strong&gt;distributed system&lt;/strong&gt;, making it easier to find slow spots and latency issues. Similarly, for logs that OpenTelemetry collects and stores in Loki, &lt;strong&gt;Grafana&lt;/strong&gt; has powerful tools for exploring and filtering logs, which helps you troubleshoot problems efficiently. The easy-to-use interface and the wide range of ways to visualize data in &lt;strong&gt;Grafana&lt;/strong&gt; make it a really valuable tool for getting useful insights from your OpenTelemetry data, ultimately making it simpler to understand how your system is behaving and find areas that need attention.&lt;/p&gt;
&lt;p&gt;Putting OpenTelemetry together for standardized data collection, &lt;strong&gt;Prometheus&lt;/strong&gt; for storing and querying metrics reliably, and &lt;strong&gt;Grafana&lt;/strong&gt; for versatile visualization and alerting gives you a complete and powerful open-source observability setup. These tools work well together, providing a flexible and cost-effective alternative to those paid observability platforms. What&amp;#39;s more, &lt;strong&gt;Grafana&lt;/strong&gt; offers special integrations and versions, like Grafana Alloy, that are specifically designed to work smoothly with OpenTelemetry, making the setup and configuration process easier and showing how much support and maturity OpenTelemetry is gaining in the industry.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In a world where software systems are getting more complex, full-stack observability is becoming essential for organizations that want to keep their applications running smoothly. OpenTelemetry is a powerful tool that helps you collect and analyze telemetry data from all parts of your system, giving you the insights you need to understand how everything works together. By using OpenTelemetry with other open-source tools like &lt;strong&gt;Prometheus&lt;/strong&gt; and &lt;strong&gt;Grafana&lt;/strong&gt;, you can create a flexible and cost-effective observability solution that helps you spot and fix problems faster, leading to better performance and happier users.&lt;/p&gt;
&lt;p&gt;This combination of OpenTelemetry, &lt;strong&gt;Prometheus&lt;/strong&gt;, and &lt;strong&gt;Grafana&lt;/strong&gt; not only simplifies the process of collecting and analyzing telemetry data but also allows you to visualize and understand your system&amp;#39;s behavior in a way that traditional monitoring tools can&amp;#39;t match. As the industry continues to embrace OpenTelemetry, it&amp;#39;s clear that this open-source framework is becoming a key player in the observability landscape, making it easier for organizations to achieve full-stack observability and improve their overall system performance.&lt;/p&gt;
&lt;p&gt;By adopting OpenTelemetry and integrating it with your existing monitoring tools, you can take a big step towards achieving a complete view of your systems, making it easier to manage complexity and ensure the reliability of your applications.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What Is Full Stack Observability? | Overview - NinjaOne, accessed on April 8, 2025, &lt;a href=&quot;https://www.ninjaone.com/blog/what-is-full-stack-observability/&quot;&gt;https://www.ninjaone.com/blog/what-is-full-stack-observability/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Full-Stack Observability: What It Is [Minus the Fluff] - Last9, accessed on April 8, 2025, &lt;a href=&quot;https://last9.io/blog/what-is-full-stack-observability/&quot;&gt;https://last9.io/blog/what-is-full-stack-observability/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is OpenTelemetry? - Elastic, accessed on April 8, 2025, &lt;a href=&quot;https://www.elastic.co/what-is/opentelemetry&quot;&gt;https://www.elastic.co/what-is/opentelemetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is OpenTelemetry? A Comprehensive Guide | Better Stack Community, accessed on April 8, 2025, &lt;a href=&quot;https://betterstack.com/community/guides/observability/what-is-opentelemetry/&quot;&gt;https://betterstack.com/community/guides/observability/what-is-opentelemetry/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenTelemetry: The key to modern enterprise observability - Elastic, accessed on April 8, 2025, &lt;a href=&quot;https://www.elastic.co/blog/opentelemetry-native-observability-business-value&quot;&gt;https://www.elastic.co/blog/opentelemetry-native-observability-business-value&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenTelemetry vs. New Relic - Which Monitoring Tool Fits You? | SigNoz, accessed on April 8, 2025, &lt;a href=&quot;https://signoz.io/comparisons/opentelemetry-vs-newrelic/&quot;&gt;https://signoz.io/comparisons/opentelemetry-vs-newrelic/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Introduction to OpenTelemetry and New Relic, accessed on April 8, 2025, &lt;a href=&quot;https://docs.newrelic.com/docs/opentelemetry/opentelemetry-introduction/&quot;&gt;https://docs.newrelic.com/docs/opentelemetry/opentelemetry-introduction/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Supercharge Your Node.js Monitoring with OpenTelemetry, Prometheus, and Grafana, accessed on April 8, 2025, &lt;a href=&quot;https://dev.to/gleidsonleite/supercharge-your-nodejs-monitoring-with-opentelemetry-prometheus-and-grafana-4mhd&quot;&gt;https://dev.to/gleidsonleite/supercharge-your-nodejs-monitoring-with-opentelemetry-prometheus-and-grafana-4mhd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Prometheus vs. OpenTelemetry Metrics: A Complete Guide - Timescale, accessed on April 8, 2025, &lt;a href=&quot;https://www.timescale.com/blog/prometheus-vs-opentelemetry-metrics-a-complete-guide&quot;&gt;https://www.timescale.com/blog/prometheus-vs-opentelemetry-metrics-a-complete-guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Integrating OpenTelemetry with Grafana for Better Observability - Last9, accessed on April 8, 2025, &lt;a href=&quot;https://last9.io/blog/opentelemetry-with-grafana/&quot;&gt;https://last9.io/blog/opentelemetry-with-grafana/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Metrics Exporter - Prometheus - OpenTelemetry, accessed on April 8, 2025, &lt;a href=&quot;https://opentelemetry.io/docs/specs/otel/metrics/sdk_exporters/prometheus/&quot;&gt;https://opentelemetry.io/docs/specs/otel/metrics/sdk_exporters/prometheus/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A practical guide to data collection with OpenTelemetry and Prometheus - Grafana, accessed on April 8, 2025, &lt;a href=&quot;https://grafana.com/blog/2023/07/20/a-practical-guide-to-data-collection-with-opentelemetry-and-prometheus/&quot;&gt;https://grafana.com/blog/2023/07/20/a-practical-guide-to-data-collection-with-opentelemetry-and-prometheus/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Complete Guide to OpenTelemetry and APM - Last9, accessed on April 8, 2025, &lt;a href=&quot;https://last9.io/blog/opentelemetry-and-apm/&quot;&gt;https://last9.io/blog/opentelemetry-and-apm/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Getting Started with OpenTelemetry [Frequently Asked Questions] - SigNoz, accessed on April 8, 2025, &lt;a href=&quot;https://signoz.io/blog/getting-started-with-opentelemetry/&quot;&gt;https://signoz.io/blog/getting-started-with-opentelemetry/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Observability</category><category>DevOps</category><category>OpenTelemetry</category><category>Monitoring</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0074-full-stack-observability-opentelemetry/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Navigating Growth: Building a Secure and Scalable AWS Environment with a Multi-Account Architecture and Control Tower</title><link>https://mkabumattar.com/blog/post/multi-account-aws-control-tower/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/multi-account-aws-control-tower/</guid><description>Learn how to leverage a multi-account AWS architecture with AWS Control Tower for enhanced security, compliance, and streamlined management. Discover best practices and FAQs.</description><pubDate>Sun, 13 Apr 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The cloud journey often kicks off with a single AWS account – it feels simple and straightforward, especially when you&amp;#39;re just starting out or have smaller teams. But as your cloud usage grows, that initial simplicity can turn into a bit of a tangled web. Suddenly, you&amp;#39;re juggling permissions for tons of users and services, trying to keep track of costs for different projects, making sure everything is secure, and figuring out those AWS service limits. This is where thinking about a &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;architecture&lt;/strong&gt; becomes really important. By smartly dividing your work and resources into separate, self-contained AWS accounts, you can build a much stronger and easier-to-manage cloud setup. And to make governing all those accounts even simpler, &lt;strong&gt;AWS&lt;/strong&gt; offers a fantastic service called &lt;strong&gt;Control Tower&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why Should You Think About a Multi-Account AWS Architecture?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;So, why bother with a &lt;strong&gt;multi-account&lt;/strong&gt; setup for your &lt;strong&gt;AWS&lt;/strong&gt; environment? Well, the main idea is to keep different types of work and resources in their own separate &lt;strong&gt;AWS&lt;/strong&gt; accounts. This separation gives you a bunch of really helpful advantages that make dealing with a large cloud environment much easier than trying to cram everything into one account.&lt;/p&gt;
&lt;p&gt;One of the biggest pluses is &lt;strong&gt;better security&lt;/strong&gt;. Think of separate accounts as strong, natural walls. By default, what&amp;#39;s in one account can&amp;#39;t be touched by another, which acts as a built-in safeguard against unauthorized access or accidental mistakes. This significantly limits the damage if something does go wrong in one area. If one account gets compromised, it usually stays contained, preventing the problem from spreading to your other important work or sensitive information in different accounts. Plus, a &lt;strong&gt;multi-account&lt;/strong&gt; approach lets you set up different security measures that are just right for each specific environment. For example, what you need for your development environment is probably very different from what you need for your live production systems. Separate accounts let you apply the right security rules to each. Some companies even have a central security account just for keeping an eye on and sending alerts for all their other accounts, giving them a bird&amp;#39;s-eye view of their security. This built-in isolation that comes with having multiple accounts creates a really solid foundation for your security, making it much harder for a problem in one place to mess up your whole cloud setup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Meeting compliance requirements&lt;/strong&gt; also becomes much easier with a &lt;strong&gt;multi-account&lt;/strong&gt; strategy. Putting sensitive work or data into its own dedicated accounts simplifies the whole process of proving you&amp;#39;re meeting regulations. For instance, if you need to follow rules like the Payment Card Industry Data Security Standard (PCI DSS) or the General Data Protection Regulation (GDPR), keeping the relevant stuff in a specific account makes it much simpler to show auditors that you&amp;#39;re doing things right. This detailed control over compliance within individual accounts helps organizations meet different rules for different types of data and work more effectively.&lt;/p&gt;
&lt;p&gt;Keeping track of &lt;strong&gt;costs&lt;/strong&gt; also gets clearer and more efficient with a &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;architecture&lt;/strong&gt;. Each account naturally becomes a way to separate and track spending. You can easily see exactly how much each account is costing, making it simpler to assign expenses to specific teams, projects, or clients. This better view of where your money is going helps teams make smarter choices about how they use resources and design their systems. While &lt;strong&gt;AWS&lt;/strong&gt; Organizations lets you combine billing for an overall view, having that fundamental cost separation at the account level gives you much more detailed financial control and accountability.&lt;/p&gt;
&lt;p&gt;From a day-to-day operations perspective, a &lt;strong&gt;multi-account&lt;/strong&gt; approach leads to &lt;strong&gt;better organization&lt;/strong&gt;. Separating work based on its purpose or environment, like having different accounts for development, testing, and your live production systems, improves overall organization and reduces the risk of accidentally messing things up between different teams or projects. Different parts of your business or different product teams often have their own ways of doing things and their own security needs. Separate accounts allow them to have more control while still following the company&amp;#39;s main rules. This separation of environments also means that changes or problems in one area are less likely to affect others, making things more stable and allowing for more flexibility.&lt;/p&gt;
&lt;p&gt;Finally, a &lt;strong&gt;multi-account&lt;/strong&gt; strategy helps you manage &lt;strong&gt;service quotas&lt;/strong&gt; more effectively. &lt;strong&gt;AWS&lt;/strong&gt; service quotas are the maximum number of resources you can have in your account, and these limits apply to each account separately. By spreading your work across multiple accounts, you can essentially increase your overall ability to use resources without hitting the limits of a single account. This stops different projects from competing for the same quotas and allows you to scale more easily as your cloud usage grows.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What Exactly is AWS Control Tower and How Does It Make Things Easier?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;So, how does &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; simplify managing all these accounts? Well, &lt;strong&gt;Control Tower&lt;/strong&gt; is a service that&amp;#39;s designed to automatically set up and govern a secure &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;AWS&lt;/strong&gt; environment. It does this by creating what&amp;#39;s called a &amp;quot;&lt;strong&gt;Landing Zone&lt;/strong&gt;,&amp;quot; which is basically a well-thought-out, &lt;strong&gt;multi-account&lt;/strong&gt; foundation built on &lt;strong&gt;AWS&lt;/strong&gt; best practices. &lt;strong&gt;Control Tower&lt;/strong&gt; works behind the scenes with several other &lt;strong&gt;AWS&lt;/strong&gt; services, like &lt;strong&gt;AWS&lt;/strong&gt; Organizations, &lt;strong&gt;AWS&lt;/strong&gt; Service Catalog, and &lt;strong&gt;AWS&lt;/strong&gt; IAM Identity Center, to give you a smooth and automated experience.&lt;/p&gt;
&lt;p&gt;One of the biggest advantages of &lt;strong&gt;Control Tower&lt;/strong&gt; is its &lt;strong&gt;automated Landing Zone setup&lt;/strong&gt;. It takes care of creating that initial &lt;strong&gt;multi-account&lt;/strong&gt; environment for you, including setting up &lt;strong&gt;AWS&lt;/strong&gt; Organizations, creating those essential first accounts (like the main management account, an audit account, and a log archive account), and organizing them into logical groups called organizational units (OUs). This whole process can take less than 30 minutes which is a huge time-saver compared to manually setting up everything yourself. This automation helps you get started with your cloud adoption faster and reduces the chance of making mistakes during the initial setup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; also gives you an &amp;quot;&lt;strong&gt;Account Factory&lt;/strong&gt;,&amp;quot; which is a standardized and automated way to create new &lt;strong&gt;AWS&lt;/strong&gt; accounts within your &lt;strong&gt;Control Tower&lt;/strong&gt; environment. Using pre-defined account templates, the &lt;strong&gt;Account Factory&lt;/strong&gt; makes sure that all new accounts are created with the right settings, ensuring consistency and compliance right from the start. This helps your organization stick to its rules and security requirements across all your accounts.&lt;/p&gt;
&lt;p&gt;Another really important feature of &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; is its &lt;strong&gt;Comprehensive Controls Management&lt;/strong&gt;, often called guardrails. These are pre-built governance rules for security, how you operate things, and compliance. You can apply these rules across your entire organization or to specific groups of accounts. These controls can either stop bad things from happening in the first place (preventive) or monitor and record activities to make sure you&amp;#39;re staying compliant (detective). These guardrails help find and fix potential security problems, keeping your &lt;strong&gt;AWS&lt;/strong&gt; environment secure and compliant. This proactive and reactive governance helps maintain a strong security and compliance stance across all your accounts, preventing rule violations and spotting any issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; also provides a &lt;strong&gt;centralized dashboard&lt;/strong&gt; that gives you a constant overview of your entire &lt;strong&gt;multi-account&lt;/strong&gt; environment. This dashboard shows you all the accounts you&amp;#39;ve set up, the controls you&amp;#39;ve enabled, and any resources that aren&amp;#39;t following the rules. Having this single place to see the health and compliance of your &lt;strong&gt;multi-account&lt;/strong&gt; setup makes monitoring and managing things much simpler for administrators.&lt;/p&gt;
&lt;p&gt;Finally, &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; works seamlessly with other key &lt;strong&gt;AWS&lt;/strong&gt; services. It&amp;#39;s built on top of &lt;strong&gt;AWS&lt;/strong&gt; Organizations for managing accounts and enforcing policies, uses &lt;strong&gt;AWS&lt;/strong&gt; Service Catalog for creating new accounts through the &lt;strong&gt;Account Factory&lt;/strong&gt;, and often integrates with &lt;strong&gt;AWS&lt;/strong&gt; IAM Identity Center (formerly &lt;strong&gt;AWS&lt;/strong&gt; SSO) for managing identities and access in one place. This integration makes it easier to use these different services together, giving you a smooth and efficient way to manage your &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;AWS&lt;/strong&gt; environment.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Landing Zones: Your Foundation for a Secure Setup&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;What exactly is a &lt;strong&gt;Landing Zone&lt;/strong&gt;, and why is it so important when you&amp;#39;re using &lt;strong&gt;Control Tower&lt;/strong&gt; to manage a &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;AWS&lt;/strong&gt; setup? A &lt;strong&gt;Landing Zone&lt;/strong&gt; is essentially a well-designed &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;AWS&lt;/strong&gt; environment that&amp;#39;s built with security and compliance best practices in mind. &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; automates the creation of this foundational environment for you. Think of it as the initial blueprint and infrastructure that gives you a secure and scalable starting point for your organization&amp;#39;s journey in the cloud.&lt;/p&gt;
&lt;p&gt;A typical &lt;strong&gt;Landing Zone&lt;/strong&gt; includes several key parts. At its heart is &lt;strong&gt;AWS&lt;/strong&gt; Organizations, which provides the structure for managing all your &lt;strong&gt;AWS&lt;/strong&gt; accounts from one place and applying company-wide rules. Within Organizations, accounts are grouped into &lt;strong&gt;Organizational Units (OUs)&lt;/strong&gt; based on what they&amp;#39;re used for or what environment they belong to. Common OUs often include a Security OU for security-related accounts and tools, and a Sandbox OU for development and testing. The &lt;strong&gt;Landing Zone&lt;/strong&gt; also sets up essential &lt;strong&gt;shared accounts&lt;/strong&gt;, usually including a management account for overall administration, an audit account for keeping centralized logs from &lt;strong&gt;AWS&lt;/strong&gt; CloudTrail and &lt;strong&gt;AWS&lt;/strong&gt; Config, and a log archive account for securely storing these logs. For managing who can access what across all these accounts, the &lt;strong&gt;Landing Zone&lt;/strong&gt; often uses &lt;strong&gt;Identity and Access Management (IAM)&lt;/strong&gt;, frequently along with &lt;strong&gt;AWS&lt;/strong&gt; IAM Identity Center for managing users and their access in one place. While &lt;strong&gt;Control Tower&lt;/strong&gt; provides the basic networking setup, you&amp;#39;ll still need to figure out your specific cross-account networking strategies. Finally, the &lt;strong&gt;Landing Zone&lt;/strong&gt; comes with an initial set of &lt;strong&gt;security and compliance controls&lt;/strong&gt; (guardrails) that are applied to the OUs or individual accounts. The way you structure your OUs within the &lt;strong&gt;Landing Zone&lt;/strong&gt; is really important because it gives you a logical way to apply your governance policies effectively. Overall, the &lt;strong&gt;Landing Zone&lt;/strong&gt; provides a consistent and repeatable foundation for deploying your applications and workloads in a &lt;strong&gt;multi-account&lt;/strong&gt; environment, making sure you have good security and compliance right from the start.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Boosting Security and Making Sure You&amp;#39;re Compliant with Control Tower&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;How exactly does &lt;strong&gt;Control Tower&lt;/strong&gt; make your &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;AWS&lt;/strong&gt; environment more secure and compliant? As we mentioned earlier, the key to &lt;strong&gt;Control Tower&amp;#39;s&lt;/strong&gt; governance is its preventive and detective controls, also known as guardrails. These controls are designed to automatically enforce your organization&amp;#39;s rules and best practices.&lt;/p&gt;
&lt;p&gt;For example, some security-focused controls might include requiring multi-factor authentication (MFA) for the main root users to protect your primary account credentials. Another important control could be to prevent public read access to your Amazon S3 buckets, stopping accidental data leaks. Making sure that &lt;strong&gt;AWS&lt;/strong&gt; CloudTrail is turned on in all your accounts is another common security control, as it gives you a record of all actions taken within your &lt;strong&gt;AWS&lt;/strong&gt; environment. You can also set up controls to stop people from creating resources in &lt;strong&gt;AWS&lt;/strong&gt; Regions that you haven&amp;#39;t approved, which can limit your attack surface and potentially save you money.&lt;/p&gt;
&lt;p&gt;When it comes to compliance, &lt;strong&gt;Control Tower&lt;/strong&gt; offers controls to enforce specific encryption standards for your data, both when it&amp;#39;s stored and when it&amp;#39;s being transferred. It can also help restrict access to sensitive data to only the accounts and users who are authorized. Furthermore, &lt;strong&gt;Control Tower&lt;/strong&gt; provides managed controls that are designed to help organizations meet digital sovereignty requirements related to where their data is stored, how access is restricted, encryption, and how resilient their systems are. &lt;strong&gt;Control Tower&lt;/strong&gt; also works with &lt;strong&gt;AWS&lt;/strong&gt; Security Hub, a service that gives you a comprehensive view of your security across all your &lt;strong&gt;AWS&lt;/strong&gt; accounts, further improving security monitoring and checks against best practices. The ability to see all your security monitoring and alerts in one place through services like Security Hub, as mentioned in the research, gives you a unified way to respond to incidents and manage your security continuously. The automated governance that &lt;strong&gt;Control Tower&amp;#39;s&lt;/strong&gt; controls provide helps organizations follow both their own internal security rules and external regulations, significantly reducing the risk of security breaches and compliance issues. The flexibility to choose and apply these controls at the OU level means you can implement security and compliance policies that are specifically tailored to the needs and risk levels of different types of work or teams.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Setting Up and Managing Your Multi-Account Environment: Practical Steps and Best Practices&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;What are the key steps and best ways to set up and manage a &lt;strong&gt;multi-account&lt;/strong&gt; environment using &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt;? The initial setup of &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; involves a few main steps. First, you need to make sure you have everything ready, like having an &lt;strong&gt;AWS&lt;/strong&gt; Organizations setup and choosing your main &lt;strong&gt;AWS&lt;/strong&gt; Region. Then, you can start the &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; setup process from the &lt;strong&gt;AWS&lt;/strong&gt; Management Console. When you&amp;#39;re setting up your &lt;strong&gt;Landing Zone&lt;/strong&gt;, you&amp;#39;ll need to pick the &lt;strong&gt;AWS&lt;/strong&gt; Regions you want to govern, enter email addresses for your shared accounts (management, audit, and log archive), and decide on your initial organizational unit (OU) structure. &lt;strong&gt;Control Tower&lt;/strong&gt; will then automatically create those initial shared accounts for you. Once your &lt;strong&gt;Landing Zone&lt;/strong&gt; is up and running, you can define and apply the security and compliance rules (guardrails) that fit your organization&amp;#39;s needs. To create new accounts within your governed environment, you&amp;#39;ll use the &lt;strong&gt;Account Factory&lt;/strong&gt;, which provides a consistent process based on pre-set templates. If you already have &lt;strong&gt;AWS&lt;/strong&gt; accounts, you can also enroll them into your &lt;strong&gt;Control Tower&lt;/strong&gt; &lt;strong&gt;Landing Zone&lt;/strong&gt; to bring them under the same management.&lt;/p&gt;
&lt;p&gt;For managing things on an ongoing basis, there are several best practices to follow. Having a well-thought-out OU structure that matches your organization&amp;#39;s structure and needs is really important for applying policies and managing resources effectively. Using a consistent tagging strategy across all your accounts is essential for accurately tracking costs, automating tasks, and managing resources efficiently. It&amp;#39;s also important to regularly review and update your controls to make sure they&amp;#39;re still relevant to the latest security threats and compliance requirements. You should also keep an eye on the &lt;strong&gt;Control Tower&lt;/strong&gt; dashboard to see the compliance status of your accounts and find any resources that aren&amp;#39;t following the rules. Clearly defining who is responsible for managing different parts of the &lt;strong&gt;multi-account&lt;/strong&gt; environment is also key for smooth operations. Automating account creation and other management tasks whenever possible can make things more efficient and reduce the chance of human error. For organizations that need more advanced customization, exploring &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; &lt;strong&gt;Account Factory&lt;/strong&gt; for Terraform (AFT) can give you more flexibility in how you create and manage accounts. A well-planned setup, along with consistent monitoring and following these best practices, is essential for getting the most out of a &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;architecture&lt;/strong&gt; managed by &lt;strong&gt;Control Tower&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Navigating the Landscape: Account Structure, Networking, and Identity Management&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;How do important architectural aspects like account structure, networking, and identity management fit into a &lt;strong&gt;Control Tower&lt;/strong&gt;-managed &lt;strong&gt;multi-account&lt;/strong&gt; environment?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Account Structure&lt;/strong&gt; within a &lt;strong&gt;Control Tower&lt;/strong&gt; environment is all about using Organizational Units (OUs) effectively to group accounts logically. Common ways to organize OUs include grouping accounts by environment (like development, testing, and production), by business unit, or by the type of work they handle. On top of this, the core shared accounts that &lt;strong&gt;Control Tower&lt;/strong&gt; sets up for you – the management account, audit account, and log archive account – form the basic structure. A well-thought-out account structure, making good use of OUs, provides a clear and logical way to apply governance rules and manage resources as you grow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Networking&lt;/strong&gt; in a &lt;strong&gt;multi-account&lt;/strong&gt; environment managed by &lt;strong&gt;Control Tower&lt;/strong&gt; needs careful planning. While &lt;strong&gt;Control Tower&lt;/strong&gt; sets up a basic framework, you&amp;#39;ll need to figure out how to enable secure communication and sharing of resources between different accounts. Options like VPC peering, &lt;strong&gt;AWS&lt;/strong&gt; Transit Gateway, and &lt;strong&gt;AWS&lt;/strong&gt; PrivateLink can be used to allow secure cross-account communication while still keeping the necessary security boundaries. Effective cross-account networking is crucial for allowing different teams and workloads in separate accounts to work together and integrate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Identity Management&lt;/strong&gt; in a &lt;strong&gt;Control Tower&lt;/strong&gt; environment often uses &lt;strong&gt;AWS&lt;/strong&gt; IAM Identity Center (formerly &lt;strong&gt;AWS&lt;/strong&gt; SSO) to centrally control who can access what across multiple accounts. This gives you the benefit of single sign-on and makes managing users easier across your entire &lt;strong&gt;multi-account&lt;/strong&gt; setup. Following the principle of least privilege, giving users only the permissions they absolutely need to do their jobs, is really important in a &lt;strong&gt;multi-account&lt;/strong&gt; environment. You can achieve this by using IAM policies within individual accounts and Service Control Policies (SCPs) that you apply at the &lt;strong&gt;AWS&lt;/strong&gt; Organizations level. Centralized identity management simplifies how users get access and allows you to apply security policies consistently across your whole &lt;strong&gt;multi-account&lt;/strong&gt; landscape.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Frequently Asked Questions (FAQ) About Multi-Account AWS with Control Tower&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What&amp;#39;s the difference between AWS Organizations and AWS Control Tower?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  &lt;strong&gt;AWS&lt;/strong&gt; Organizations is the foundational service that lets you manage
  multiple &lt;strong&gt;AWS&lt;/strong&gt; accounts from one place, offering features like combined
  billing and the ability to apply policy-based controls (Service Control
  Policies or SCPs) across your accounts. &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; builds on
  top of &lt;strong&gt;AWS&lt;/strong&gt; Organizations by giving you an automated and guided way to set
  up and govern a secure &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;AWS&lt;/strong&gt; environment. It creates a
  &lt;strong&gt;Landing Zone&lt;/strong&gt; based on best practices, offers an &lt;strong&gt;Account Factory&lt;/strong&gt; for
  easily creating new accounts, and provides pre-built controls (guardrails) for
  security, operations, and compliance. Think of &lt;strong&gt;Control Tower&lt;/strong&gt; as
  simplifying and automating many of the tasks involved in setting up and
  managing a &lt;strong&gt;multi-account&lt;/strong&gt; environment using Organizations.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;Does it cost extra to use AWS Control Tower?&quot;&gt;
  Nope, there&apos;s no additional charge for using **AWS** **Control Tower** itself.
  You only pay for the underlying **AWS** services that **Control Tower** sets
  up and manages for you, like the resources in your individual **AWS**
  accounts, **AWS** Organizations, **AWS** Service Catalog, and **AWS** IAM
  Identity Center.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Can I use AWS Control Tower with my AWS accounts that I already have?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Yes, &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; lets you enroll your existing &lt;strong&gt;AWS&lt;/strong&gt; accounts
  into your &lt;strong&gt;Control Tower&lt;/strong&gt; &lt;strong&gt;Landing Zone&lt;/strong&gt;. This means you can bring your
  current accounts under the same management and security policies that
  &lt;strong&gt;Control Tower&lt;/strong&gt; provides.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What if I need more customization than what Control Tower offers right out of the box?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  While &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; gives you a structured approach based on best
  practices, it also has options for customization. &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt;
  &lt;strong&gt;Account Factory&lt;/strong&gt; for Terraform (AFT) allows for more advanced customization
  of how you create new accounts using code. You can also create your own custom
  controls to meet specific needs that go beyond the pre-built guardrails.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does Control Tower help with making sure I&amp;#39;m compliant?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; helps with compliance by providing those preventive
  and detective controls (guardrails) that automatically enforce your compliance
  rules across your &lt;strong&gt;multi-account&lt;/strong&gt; environment. You can apply these controls
  at the organizational unit (OU) level to tailor compliance requirements to
  specific groups of accounts. Plus, it works with services like &lt;strong&gt;AWS&lt;/strong&gt;
  Security Hub to continuously monitor and help you spot any areas where you
  might not be meeting your desired compliance standards.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;When should I think about using a multi-account architecture with Control Tower?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  You should consider moving to a &lt;strong&gt;multi-account&lt;/strong&gt; setup with &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control
  Tower&lt;/strong&gt; when your &lt;strong&gt;AWS&lt;/strong&gt; usage starts to grow and you have different teams or
  types of work that have different security, compliance, or operational needs.
  It&amp;#39;s also a good idea if you need better ways to separate and see your costs,
  if you need strong security boundaries, or if you want to improve your overall
  management and security in the cloud. Even smaller organizations can benefit
  from the organized and secure approach that a &lt;strong&gt;multi-account&lt;/strong&gt; strategy with
  &lt;strong&gt;Control Tower&lt;/strong&gt; provides.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion: Embrace the Power of Multi-Account AWS with Control Tower&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Moving to a &lt;strong&gt;multi-account&lt;/strong&gt; &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;architecture&lt;/strong&gt; offers some really significant advantages for organizations that want to build a secure, scalable, and well-managed cloud environment. You get better security by keeping things isolated, compliance becomes simpler by separating different types of work, managing costs is easier with clear breakdowns, operations run more smoothly by having separate environments, and you can handle service limits more effectively as you grow. &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; makes setting up and managing this kind of environment much easier. Its automated &lt;strong&gt;Landing Zone&lt;/strong&gt; setup, standardized &lt;strong&gt;Account Factory&lt;/strong&gt;, comprehensive controls, and central dashboard give you a powerful set of tools for effectively managing multiple &lt;strong&gt;AWS&lt;/strong&gt; accounts. By using &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt;, organizations can confidently handle the complexities of cloud growth, maintain strong security and compliance, and ultimately focus on innovating and delivering value to their customers. If you&amp;#39;re serious about building a robust and future-proof &lt;strong&gt;AWS&lt;/strong&gt; infrastructure, exploring &lt;strong&gt;AWS&lt;/strong&gt; &lt;strong&gt;Control Tower&lt;/strong&gt; is a crucial step.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Build an AWS Multi-Account Strategy According to Best Practices - Spacelift, accessed on April 6, 2025, &lt;a href=&quot;https://spacelift.io/blog/aws-multi-account-strategy&quot;&gt;https://spacelift.io/blog/aws-multi-account-strategy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Benefits of using multiple AWS accounts - AWS Documentation, accessed on April 6, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/accounts/latest/reference/welcome-multiple-accounts.html&quot;&gt;https://docs.aws.amazon.com/accounts/latest/reference/welcome-multiple-accounts.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Organizing Your AWS Environment Using Multiple Accounts, accessed on April 6, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/organizing-your-aws-environment.html&quot;&gt;https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/organizing-your-aws-environment.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Benefits of using multiple AWS accounts - Organizing Your AWS Environment Using Multiple Accounts - AWS Documentation, accessed on April 6, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/benefits-of-using-multiple-aws-accounts.html&quot;&gt;https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/benefits-of-using-multiple-aws-accounts.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS multi-account strategy for your AWS Control Tower landing zone - AWS Documentation, accessed on April 6, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/controltower/latest/userguide/aws-multi-account-landing-zone.html&quot;&gt;https://docs.aws.amazon.com/controltower/latest/userguide/aws-multi-account-landing-zone.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Multi-account strategy for small and medium businesses | AWS Cloud Operations Blog, accessed on April 6, 2025, &lt;a href=&quot;https://aws.amazon.com/blogs/mt/multi-account-strategy-for-small-and-medium-businesses/&quot;&gt;https://aws.amazon.com/blogs/mt/multi-account-strategy-for-small-and-medium-businesses/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Control Tower FAQs - Amazon Web Services, accessed on April 6, 2025, &lt;a href=&quot;https://aws.amazon.com/controltower/faqs/&quot;&gt;https://aws.amazon.com/controltower/faqs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is AWS Control Tower? - nOps, accessed on April 6, 2025, &lt;a href=&quot;https://www.nops.io/glossary/what-is-aws-control-tower/&quot;&gt;https://www.nops.io/glossary/what-is-aws-control-tower/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Control Tower - AWS Documentation, accessed on April 6, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/controltower/latest/userguide/what-is-control-tower.html&quot;&gt;https://docs.aws.amazon.com/controltower/latest/userguide/what-is-control-tower.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cloud Security Governance - AWS Control Tower, accessed on April 6, 2025, &lt;a href=&quot;https://aws.amazon.com/controltower/&quot;&gt;https://aws.amazon.com/controltower/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Control Tower Features, accessed on April 6, 2025, &lt;a href=&quot;https://aws.amazon.com/controltower/features/&quot;&gt;https://aws.amazon.com/controltower/features/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Control Tower and AWS Organizations, accessed on April 6, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/organizations/latest/userguide/services-that-can-integrate-CTower.html&quot;&gt;https://docs.aws.amazon.com/organizations/latest/userguide/services-that-can-integrate-CTower.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Manage Accounts Through AWS Organizations - AWS Control Tower - AWS Documentation, accessed on April 6, 2025, &lt;a href=&quot;https://docs.aws.amazon.com/controltower/latest/userguide/organizations.html&quot;&gt;https://docs.aws.amazon.com/controltower/latest/userguide/organizations.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Cloud Computing</category><category>AWS</category><category>DevOps</category><category>Cloud Security</category><category>Cloud Architecture</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0073-multi-account-aws-control-tower/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Policy as Code with Open Policy Agent: A Technical and Governance Perspective</title><link>https://mkabumattar.com/blog/post/policy-as-code-opa-guide/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/policy-as-code-opa-guide/</guid><description>Learn how to use Policy as Code with Open Policy Agent (OPA) to boost your cloud governance, security, and compliance. This guide covers the basics, benefits, how to integrate with Terraform and Kubernetes, common challenges, and real-world examples.</description><pubDate>Tue, 08 Apr 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Think about how much stuff modern organizations have running in the cloud these days. It&amp;#39;s a lot, right? All those servers, applications, and connections can get pretty complicated to manage. Just clicking around in a console or trying to keep track of everything in spreadsheets? That doesn&amp;#39;t really cut it anymore if you want to stay secure, meet your compliance rules, and generally keep things under control. That&amp;#39;s where this idea of &amp;quot;policy as code&amp;quot; comes in. It&amp;#39;s a way of saying, &amp;quot;Hey, let&amp;#39;s use code to define and manage the rules that govern our tech stuff.&amp;quot; And one of the coolest tools out there for this is the Open Policy Agent, or OPA for short. It&amp;#39;s like a universal rulebook that can help you bring order to all sorts of different environments.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What Exactly is Policy as Code, and Why Should You Care?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Okay, so what&amp;#39;s the big deal with policy as code? Well, instead of having your important rules locked away in documents or spreadsheets that people might forget about or misinterpret, policy as code means you write those rules down in a way that computers can understand – as actual code. Think of it like this: you&amp;#39;re taking the guidelines for how your systems should behave and turning them into something like JSON or YAML files that software can read and act on. This is a huge step up from the old way of doing things, where you relied on people to manually check stuff, which, let&amp;#39;s be honest, can lead to mistakes. When you treat your policies like real code, you can use all the same smart techniques that developers use to make sure their software is reliable and efficient.&lt;/p&gt;
&lt;p&gt;Policy as code works because it follows some pretty smart principles. First off, it uses a &lt;strong&gt;declarative language&lt;/strong&gt;. That just means you describe what you want the end result to be, not the step-by-step instructions on how to get there. This makes your policies much clearer and easier to write because you&amp;#39;re focusing on the goal. Second, because it&amp;#39;s &lt;strong&gt;machine-readable&lt;/strong&gt;, your policies can easily talk to different systems and tools, making automation a breeze. Third, just like with regular code, you can use &lt;strong&gt;version control&lt;/strong&gt; to keep track of changes, see who did what, and work together with your team. And finally, &lt;strong&gt;automation&lt;/strong&gt; is key. Your systems can automatically enforce these policies, so you don&amp;#39;t have to rely on manual checks, which makes everything much more consistent. Put it all together, and you&amp;#39;ve got policies that are clear, consistent, auditable, and enforced without a ton of manual effort.&lt;/p&gt;
&lt;p&gt;Why should you actually care about all this? Well, the benefits are pretty awesome. You get &lt;strong&gt;more automation and consistency&lt;/strong&gt;, which means your systems behave more predictably. You also get &lt;strong&gt;better security and compliance&lt;/strong&gt; because you&amp;#39;ve got automated checks constantly making sure you&amp;#39;re following the rules. This also leads to &lt;strong&gt;faster and safer software releases&lt;/strong&gt; because your policies are baked right into the development process. Compared to doing things by hand, policy as code is way more &lt;strong&gt;efficient, faster, gives you better visibility, improves collaboration, and is more accurate&lt;/strong&gt;. Being able to see how policies have changed over time and having automated testing in place makes everything much more solid. Ultimately, by automating how you manage your policies, you can seriously cut down on human errors and keep your environments much more stable and secure.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Meet OPA: Your Unified Policy Engine for the Cloud&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When it comes to policy as code, the &lt;strong&gt;Open Policy Agent (OPA)&lt;/strong&gt; is a real standout. People often just call it &amp;quot;Oh-pa.&amp;quot; It&amp;#39;s an open-source tool that&amp;#39;s designed to be a single place to manage all your policies, no matter what part of your tech stack they apply to. It&amp;#39;s even a graduate of the Cloud Native Computing Foundation (CNCF), which means it&amp;#39;s a well-trusted and reliable piece of tech for managing policies in today&amp;#39;s cloud world. Because OPA can work across so many different services and platforms, it&amp;#39;s super helpful for organizations that want a consistent way to handle policies, making things less complicated and easier to govern.&lt;/p&gt;
&lt;p&gt;OPA works by doing something really smart: it &lt;strong&gt;separates the decision of whether something is allowed from actually enforcing that decision&lt;/strong&gt;. When a system needs to know if an action should be permitted, it sends &lt;strong&gt;input&lt;/strong&gt; to OPA as structured data, usually in JSON format. Then, OPA takes that input and checks it against the &lt;strong&gt;policies&lt;/strong&gt; you&amp;#39;ve defined, which are written in its special language called &lt;strong&gt;Rego&lt;/strong&gt;. This involves a &lt;strong&gt;query&lt;/strong&gt; based on the input and your policies, and OPA spits out an &lt;strong&gt;output&lt;/strong&gt; that says what the policy decision is. Rego itself is based on simple if-then logic, so you can create rules that clearly state when something is allowed or not. Plus, OPA has a &lt;strong&gt;REST API&lt;/strong&gt; that lets you manage your policies and ask for policy decisions, making it easy to connect with all sorts of systems and applications. This separation means that developers can focus on building their apps, while security and operations teams can handle the policies independently. And because Rego is declarative, it&amp;#39;s easier to just say what you want to achieve with your policies.&lt;/p&gt;
&lt;p&gt;OPA&amp;#39;s brain, its architecture, has a few key parts that work together to figure out if a policy is being followed. The &lt;strong&gt;Policy Engine (OPA Core)&lt;/strong&gt; is the main processor. It takes your policy questions and compares them to the policies and data you&amp;#39;ve loaded in. &lt;strong&gt;Rego&lt;/strong&gt;, that special &lt;strong&gt;Policy Language&lt;/strong&gt;, gives you a clear way to write down your policy rules. &lt;strong&gt;Input Data&lt;/strong&gt;, usually in JSON, gives the engine the context it needs to make a decision. &lt;strong&gt;Policies&lt;/strong&gt;, written in Rego, are where you put your specific rules and logic. And finally, the &lt;strong&gt;Policy Decisions (Output)&lt;/strong&gt; are what OPA tells you – whether something is allowed or denied, or maybe some other useful information based on your policies. Understanding these pieces is super important if you want to use OPA effectively in your tech setup.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;How Does Policy as Code with OPA Bolster Your Compliance, Security, and Governance?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Using policy as code with OPA can really help you get a better handle on three crucial things: compliance, security, and governance.&lt;/p&gt;
&lt;p&gt;When it comes to &lt;strong&gt;compliance&lt;/strong&gt;, OPA can automatically check if you&amp;#39;re meeting various regulations like GDPR, HIPAA, and PCI DSS. You just write these requirements as Rego policies, and OPA can constantly monitor and make sure you&amp;#39;re following them, which lowers the risk of getting into trouble. OPA can even create &lt;strong&gt;reports in real-time&lt;/strong&gt; that show you which systems aren&amp;#39;t compliant and tell you exactly which policies they&amp;#39;re breaking. Plus, it keeps &lt;strong&gt;audit logs&lt;/strong&gt; of all the policy enforcement, so you know who did what and when, which makes compliance audits much easier and gives you proof that you&amp;#39;re doing things right. This automation of compliance stuff saves a ton of time and effort compared to manual checks, helping you stay on the right side of the law and industry standards.&lt;/p&gt;
&lt;p&gt;From a &lt;strong&gt;security&lt;/strong&gt; standpoint, policy as code with OPA lets you proactively enforce security best practices. This includes things like making sure people only have the &lt;strong&gt;minimum access they need&lt;/strong&gt;, setting up &lt;strong&gt;network boundaries&lt;/strong&gt;, and making sure &lt;strong&gt;data is encrypted&lt;/strong&gt;. You can also set up OPA to &lt;strong&gt;prevent risky things from being deployed&lt;/strong&gt;, like unapproved software or container images from unknown sources. You can even limit access to resources based on things like the time of day, where someone is located, or their job role. By writing your security rules as code, you can automatically enforce them across your entire infrastructure and applications, making it harder for bad guys to get in and reducing the chances of security breaches. This proactive approach really beefs up your overall security.&lt;/p&gt;
&lt;p&gt;In the world of &lt;strong&gt;governance&lt;/strong&gt;, OPA makes it easier to use modern ways of developing and running software like DevOps, DevSecOps, and GitOps. By putting your policies into a clear, computer-readable format, OPA makes sure your &lt;strong&gt;policies are consistent&lt;/strong&gt; across everything, from your infrastructure to your applications. You can even use it to &lt;strong&gt;keep costs down&lt;/strong&gt; by setting limits on how much you spend on cloud resources and getting alerts or even stopping deployments that go over budget. OPA also helps with governance by &lt;strong&gt;checking if configuration changes and new deployments follow your rules before they even happen&lt;/strong&gt;. This helps prevent mistakes and makes sure everything aligns with your organization&amp;#39;s standards. Finally, policy as code with OPA helps &lt;strong&gt;clarify who owns and is responsible for policies&lt;/strong&gt; because they&amp;#39;re explicitly defined and managed as code, making it easier to know who to talk to if something needs to be changed. This unified and automated way of managing policies gives you better visibility and control, leading to more effective governance across your organization.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Policy as Code in Action: Integrating OPA with Terraform for Infrastructure Governance&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The idea of policy as code really shines when you combine OPA with tools like &lt;strong&gt;Terraform&lt;/strong&gt; that let you manage your infrastructure as code. Terraform lets you define and set up your infrastructure using code, and when you add OPA to the mix, you can enforce your policies right within your infrastructure workflows. This is super useful because it means you can &lt;strong&gt;check if your infrastructure changes are okay before they&amp;#39;re even made&lt;/strong&gt;, catching any compliance or security problems early on. By governing your infrastructure deployments proactively, you can stop non-compliant resources from being created in the first place, leading to more secure and well-managed environments.&lt;/p&gt;
&lt;p&gt;The typical &lt;strong&gt;process of using OPA with Terraform&lt;/strong&gt; involves a few key steps. First, Terraform creates a &lt;strong&gt;plan as a JSON file&lt;/strong&gt;, which shows all the changes it&amp;#39;s going to make to your infrastructure. Then, you write &lt;strong&gt;OPA policies in Rego&lt;/strong&gt; to look at this plan and decide if it meets your rules. You can then use the &lt;strong&gt;OPA command-line tool&lt;/strong&gt; or a special &lt;strong&gt;Terraform integration&lt;/strong&gt; to compare the plan against your policies. Based on what &lt;strong&gt;OPA says&lt;/strong&gt; (either &amp;quot;go ahead&amp;quot; or &amp;quot;stop&amp;quot;), you can then either apply the Terraform plan or hold off and fix any policy violations. This makes sure that all your infrastructure changes are checked against your rules before they&amp;#39;re actually put in place, making everything more consistent and reducing the risk of mistakes. The fact that the Terraform plan is in JSON format makes it easy for OPA to look at all the details of each resource and enforce policies based on those details.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a simple example of a Rego policy you could use with Terraform to make sure all your AWS resources have certain tags:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package terraform.checks

# Define the tags we absolutely need
required_tags := {&amp;quot;environment&amp;quot;, &amp;quot;project&amp;quot;, &amp;quot;owner&amp;quot;}

# If an AWS resource is missing a required tag, say no
deny contains msg if {
  resource := input.resource_changes[_]
  resource.type == &amp;quot;aws_instance&amp;quot; or resource.type == &amp;quot;aws_s3_bucket&amp;quot; # Add other AWS resource types here
  missing_tag := required_tags - object.get(resource.change.after.tags, _)
  count(missing_tag) &amp;gt; 0

  msg := sprintf(&amp;quot;Resource &amp;#39;%s&amp;#39; is missing these required tags: %v&amp;quot;, [resource.address, missing_tag])
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This policy looks at all the changes Terraform is planning to make. For any aws_instance or aws_s3_bucket (you can add other types too), it checks if the tags that are supposed to be there after the change include all the tags in our required_tags list. If any are missing, it creates a message saying which resource is missing which tags and denies the change.&lt;/p&gt;
&lt;p&gt;There are tons of &lt;strong&gt;other ways you can use OPA with Terraform&lt;/strong&gt;. For example, you could &lt;strong&gt;restrict SSH access&lt;/strong&gt; to your public servers to only allow connections from specific, approved IP addresses. You could also make sure that &lt;strong&gt;all your S3 buckets have encryption enabled&lt;/strong&gt; before they&amp;#39;re created, keeping your data safe. And you could even &lt;strong&gt;limit the types of servers or cloud providers&lt;/strong&gt; you&amp;#39;re allowed to use to help control costs or stick to company standards. These are just a few examples of how flexible and powerful OPA can be when it comes to enforcing infrastructure policies with Terraform.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Governing Your Container Orchestration: Leveraging OPA with Kubernetes&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Policy as code with OPA isn&amp;#39;t just for infrastructure; it also works great with container platforms like &lt;strong&gt;Kubernetes&lt;/strong&gt;, giving you a strong way to manage these dynamic environments. You can use OPA as a &lt;strong&gt;Kubernetes admission controller&lt;/strong&gt;, which basically means it intercepts requests to the Kubernetes API server and checks if they follow your rules before letting them create or update things. A popular tool that makes this easier is &lt;strong&gt;OPA Gatekeeper&lt;/strong&gt;. It&amp;#39;s a special Kubernetes component that helps you define and enforce these policies. By using OPA in this way, you can make sure your Kubernetes clusters are following security, compliance, and operational best practices.&lt;/p&gt;
&lt;p&gt;OPA can do a lot of cool things within Kubernetes to help with governance. You can set policies to &lt;strong&gt;require resource limits&lt;/strong&gt; (like CPU and memory) for all your containers, making sure you&amp;#39;re using your resources efficiently and preventing any one container from hogging everything. Another important use case is &lt;strong&gt;only allowing images from trusted registries&lt;/strong&gt;, which helps protect you from deploying containers with known security problems. OPA can also make sure you have &lt;strong&gt;mandatory labels&lt;/strong&gt; on your Kubernetes resources like namespaces, deployments, and pods, which is really helpful for organizing things, tracking costs, and enforcing policies based on specific attributes. You can even define policies to &lt;strong&gt;restrict the use of privileged containers&lt;/strong&gt;, which improves your cluster&amp;#39;s security by limiting what those containers can do. OPA can also help you &lt;strong&gt;control network policies&lt;/strong&gt; and &lt;strong&gt;how services talk to each other&lt;/strong&gt;, ensuring that only authorized communication happens within your Kubernetes environment. These are just some of the ways OPA can help you enforce governance in Kubernetes.&lt;/p&gt;
&lt;p&gt;The typical &lt;strong&gt;workflow for using OPA with Kubernetes&lt;/strong&gt; involves first installing &lt;strong&gt;OPA Gatekeeper&lt;/strong&gt; into your Kubernetes cluster. Then, you define your policies as &lt;strong&gt;Constraint Templates&lt;/strong&gt;, which are written in Rego, and configure them using &lt;strong&gt;Constraints&lt;/strong&gt;, which are special Kubernetes resources. When someone tries to create or change something in Kubernetes, the &lt;strong&gt;Kubernetes API server sends a request to OPA Gatekeeper&lt;/strong&gt;. &lt;strong&gt;OPA then checks this request&lt;/strong&gt; against the policies you&amp;#39;ve defined. Finally, &lt;strong&gt;OPA Gatekeeper tells the Kubernetes API server whether to allow or deny the request&lt;/strong&gt;, and Kubernetes enforces that decision. This smooth integration makes sure that every change in your Kubernetes cluster is validated against your governance rules, leading to a more secure and compliant setup.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Navigating the Hurdles: Common Challenges and Solutions in Implementing OPA for Policy as Code&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While using policy as code with OPA has a lot of advantages, you might run into some challenges when you&amp;#39;re first getting started. One common issue is the &lt;strong&gt;complexity&lt;/strong&gt; of adopting a whole new way of thinking and getting it to work with your existing systems. Learning &lt;strong&gt;Rego&lt;/strong&gt;, OPA&amp;#39;s policy language, can also be a bit of a curve, especially if your team isn&amp;#39;t used to declarative programming. Plus, it often requires a &lt;strong&gt;shift in how your teams work&lt;/strong&gt;, as they need to get used to defining and enforcing policies in a new way. If you&amp;#39;re a big company with lots of different technologies, managing all those &lt;strong&gt;different systems&lt;/strong&gt; and getting them to work with OPA can be tricky. Meeting &lt;strong&gt;strict audit and compliance requirements&lt;/strong&gt; often means you need a really good understanding of both the regulations and what OPA can do. Making sure OPA runs &lt;strong&gt;efficiently and can handle a large scale&lt;/strong&gt; in complex environments can also be a challenge. And if your policies aren&amp;#39;t written and tested well, they could even introduce &lt;strong&gt;new security problems&lt;/strong&gt;. Keeping track of and managing the &lt;strong&gt;different versions of your policies&lt;/strong&gt; across your infrastructure is another thing you&amp;#39;ll need to figure out. Lastly, the open-source version of OPA doesn&amp;#39;t have a lot of &lt;strong&gt;built-in tools for monitoring and managing&lt;/strong&gt; it, which can make it harder to use at a large scale.&lt;/p&gt;
&lt;p&gt;To get past these challenges, there are several things you can do. It&amp;#39;s really important to &lt;strong&gt;start with clear goals&lt;/strong&gt; for your policies and to &lt;strong&gt;design them in a modular way&lt;/strong&gt;, breaking down big, complicated policies into smaller, easier-to-manage pieces. You should also treat your &lt;strong&gt;Rego policies like any other code&lt;/strong&gt;, using version control, testing them thoroughly, and integrating them into your CI/CD pipelines to make sure they&amp;#39;re reliable. Using &lt;strong&gt;well-defined permission models&lt;/strong&gt; and keeping your policy code separate from your application code can also make things more secure and easier to manage. Separating the structure of your data from the actual data in your policies can also make them clearer. Making sure the &lt;strong&gt;OPA agent itself is secure&lt;/strong&gt; through proper setup and access controls is also crucial. You might also want to look at using &lt;strong&gt;higher-level tools or interfaces&lt;/strong&gt; that make it easier to write Rego policies. Using &lt;strong&gt;centralized policy management solutions&lt;/strong&gt;, like Styra DAS, can help with distributing policies, monitoring them, and governing them at scale. Setting up &lt;strong&gt;clear rules and standards for your policies&lt;/strong&gt; and encouraging &lt;strong&gt;collaboration and knowledge sharing&lt;/strong&gt; among your teams are also key to making this work. And finally, you should &lt;strong&gt;log and monitor&lt;/strong&gt; how your policies are being enforced and &lt;strong&gt;regularly review and update them&lt;/strong&gt; to make sure they&amp;#39;re still effective. Overcoming these challenges takes a comprehensive approach that includes technical best practices, changes in how your organization works, and maybe even using some specialized tools.&lt;/p&gt;
&lt;p&gt;To give you a better idea of what tools are out there for policy as code, here&amp;#39;s a quick comparison of some popular options:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Tool&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Strengths&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Weaknesses&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Open Policy Agent (OPA)&lt;/td&gt;
&lt;td&gt;General-purpose policy engine&lt;/td&gt;
&lt;td&gt;Customizable, supports multiple languages&lt;/td&gt;
&lt;td&gt;Can have a steeper learning curve&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HashiCorp Sentinel&lt;/td&gt;
&lt;td&gt;Policy as Code framework&lt;/td&gt;
&lt;td&gt;Easy to use, works well with Terraform&lt;/td&gt;
&lt;td&gt;Less flexible in terms of customization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Config Rules&lt;/td&gt;
&lt;td&gt;Policy evaluation for AWS services&lt;/td&gt;
&lt;td&gt;Integrates seamlessly with AWS&lt;/td&gt;
&lt;td&gt;Primarily focused on AWS environments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terraform&lt;/td&gt;
&lt;td&gt;Infrastructure as Code with policy features&lt;/td&gt;
&lt;td&gt;Widely adopted, relatively easy to use&lt;/td&gt;
&lt;td&gt;Policy enforcement capabilities are somewhat limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conftest&lt;/td&gt;
&lt;td&gt;Policy as Code tool for Kubernetes&lt;/td&gt;
&lt;td&gt;Simple to use, integrates well with Kubernetes&lt;/td&gt;
&lt;td&gt;Mostly focused on Kubernetes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regula&lt;/td&gt;
&lt;td&gt;Policy as Code for cloud infrastructure&lt;/td&gt;
&lt;td&gt;Easy to use, supports multiple cloud providers&lt;/td&gt;
&lt;td&gt;Might not be as customizable for very specific needs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;This table gives you a quick overview of some of the main players in the policy as code space, highlighting what they do best and where they might fall short. When choosing a tool, think carefully about what you need, what your team is comfortable with, and what your current infrastructure looks like.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Your Burning Questions Answered: Frequently Asked Questions about Policy as Code and OPA&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To help clear up any confusion and answer some common questions, here are some FAQs about policy as code and OPA:&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What is Policy as Code and how does it impact cloud security?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Policy as Code automates the governance and compliance of your code and how it
  runs. This makes sure everything follows your organization&amp;#39;s rules and any
  legal requirements. By automating security policies and immediately spotting
  any violations, it really helps improve cloud security.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does Policy as Code improve data compliance in the cloud?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  By automatically checking and consistently enforcing policies about how data
  is stored, kept, and protected, Policy as Code helps you meet regulations like
  GDPR and PCI DSS, reducing the chances of compliance issues.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;Which are some of the most popular Policy as Code tools?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Besides Open Policy Agent (OPA) and HashiCorp Sentinel, other popular tools
  include AWS Config Rules, Terraform (which has some policy features), Conftest
  (for Kubernetes), and Regula (for cloud infrastructure).
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How does Policy as Code prevent cloud configuration drifts?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Policy as Code makes sure that the way your cloud resources should be set up
  is defined and enforced through code. It constantly checks if the actual setup
  matches what you&amp;#39;ve defined, and can even automatically fix any differences.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;How do I make user attributes stored in LDAP/AD available to OPA?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  You&amp;#39;ve got a few options: you can include user info in JSON Web Tokens (JWTs),
  set up OPA to regularly sync with LDAP/AD, or write OPA policies that directly
  query LDAP/AD when they need user information.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;How does OPA do conflict resolution?&quot;&gt;
  In Rego, you can have rules that both allow and deny something. It&apos;s up to
  you, the policy writer, to decide which one takes precedence. Often, you&apos;ll
  define a special document (like authz) where you set the logic for how to
  resolve these conflicts. You can also use the else keyword to give priority to
  certain rules.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Does statement order matter in Rego?&quot;&gt;
  Generally, no. The order in which you write your statements in Rego doesn&apos;t
  usually change how the policy works. However, you can use the else keyword to
  make the order matter, allowing more specific rules to override more general
  ones based on their position.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Which equality operator should I use in Rego?&quot;&gt;
  Rego has a few: := for assigning values to local variables, == for comparing
  if two values are the same, and = which does both assignment and comparison.
  It&apos;s generally best to use := for declaring variables and == for checking if
  things are equal whenever you can, as it makes your code easier to read and
  maintain.
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;How can multiple teams collaborate using OPA?&quot;&gt;
  OPA lets different teams write their policies in separate &quot;packages.&quot; Then,
  you can have a central policy that &quot;imports&quot; these team policies and combines
  their decisions, giving you a flexible way for everyone to contribute to the
  overall policy framework.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What are the performance considerations with OPA?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  For situations where speed is critical, try to write policies that don&amp;#39;t
  involve a lot of looping or searching. Using objects instead of arrays when
  you have a unique identifier can help. Also, simple equality checks can
  improve performance by allowing OPA to index rules effectively. For more
  complex policies, you might look into &amp;quot;partial evaluation&amp;quot; to optimize them.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;Accordion client:load title=&quot;What is Rego and why use it?&quot;&gt;
  Rego is the special policy language that OPA uses. It&apos;s designed specifically
  for working with structured data like JSON, making it easy to write policies
  for things like authorization, checking configurations, and filtering data.
&lt;/Accordion&gt;&lt;p&gt;&amp;lt;Accordion
  client:load
  title=&amp;quot;What is the difference between authentication and authorization?&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;  Authentication is about verifying who a user is, while authorization is about
  determining what an authenticated user is allowed to do with specific
  resources. Policy as code with OPA is mainly focused on the authorization
  part.
&lt;/Accordion&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Seeing is Believing: Real-World Success Stories of Policy as Code with OPA&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Lots of organizations have successfully adopted policy as code with OPA to improve their security, compliance, and governance. Big names like &lt;strong&gt;Netflix&lt;/strong&gt; and &lt;strong&gt;Pinterest&lt;/strong&gt;, who were early adopters, even built their own custom systems to manage OPA at scale, showing how adaptable it is for large, complex environments.&lt;/p&gt;
&lt;p&gt;OPA is being used in all sorts of different areas. In &lt;strong&gt;payment processing&lt;/strong&gt;, it helps with fine-grained authorization based on things like how long an authorization is valid, the permission level, and details about the bank accounts and transaction amount. Banks and other financial institutions use OPA for &lt;strong&gt;role-based access control (RBAC)&lt;/strong&gt;, giving specific employees access to business bank accounts based on their roles and permissions. Even weather forecasting companies use OPA to manage who can access their APIs, controlling which third-party apps can get specific weather data based on various criteria.&lt;/p&gt;
&lt;p&gt;Beyond just application-level access, OPA has been really helpful in making sure cloud environments are &lt;strong&gt;secure and compliant&lt;/strong&gt;. Organizations use OPA to ensure their cloud infrastructure follows internal standards and regulatory requirements, like CIS benchmarks and SOC 2 compliance. When it comes to &lt;strong&gt;Kubernetes&lt;/strong&gt;, OPA is widely used for &lt;strong&gt;admission control&lt;/strong&gt;, enforcing policies about resource limits, which software sources are allowed, and preventing the use of risky &amp;quot;privileged&amp;quot; containers. OPA is also used for &lt;strong&gt;API authorization and making sure only necessary access is granted&lt;/strong&gt; in microservices setups, ensuring that only authorized services can talk to each other. It&amp;#39;s even used as a &lt;strong&gt;control engine in CI/CD pipelines&lt;/strong&gt;, checking configurations and compliance during the development process. These real-world examples show just how much of an impact policy as code with OPA is having across different kinds of technology.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion: Embracing Policy as Code with OPA for Robust Cloud Governance&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In today&amp;#39;s fast-paced tech world, managing the growing complexity of cloud environments requires a more automated and reliable approach to policies. Policy as code, especially with the Open Policy Agent, offers a powerful way to tackle these challenges. By defining, managing, and enforcing policies through code, organizations can achieve new levels of automation, consistency, security, and compliance. OPA&amp;#39;s flexibility as a central policy engine, combined with the power of its Rego language, allows teams to implement detailed controls across their entire technology stack, from infrastructure as code to container orchestration and even application-level access. While getting started with policy as code and OPA might have a few bumps in the road, the long-term benefits of better governance, stronger security, and smoother compliance make it an essential tool for any organization aiming for solid cloud governance in the modern era. Adopting this way of thinking is no longer just a good idea; it&amp;#39;s becoming a must for navigating the complexities of the digital world with confidence and control.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What is Policy as Code (PaC)? - CrowdStrike, accessed on April 6, 2025, &lt;a href=&quot;https://www.crowdstrike.com/en-us/cybersecurity-101/cloud-security/policy-as-code/&quot;&gt;https://www.crowdstrike.com/en-us/cybersecurity-101/cloud-security/policy-as-code/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Policy as Code | Sentinel - HashiCorp Developer, accessed on April 6, 2025, &lt;a href=&quot;https://developer.hashicorp.com/sentinel/docs/concepts/policy-as-code&quot;&gt;https://developer.hashicorp.com/sentinel/docs/concepts/policy-as-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Policy as Code? - Permit.io, accessed on April 6, 2025, &lt;a href=&quot;https://www.permit.io/blog/what-is-policy-as-code&quot;&gt;https://www.permit.io/blog/what-is-policy-as-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Documentation - Open Policy Agent, accessed on April 6, 2025, &lt;a href=&quot;https://www.openpolicyagent.org/docs/latest/&quot;&gt;https://www.openpolicyagent.org/docs/latest/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is an Open Policy Agent (OPA)? - Sysdig, accessed on April 6, 2025, &lt;a href=&quot;https://sysdig.com/learn-cloud-native/what-is-an-open-policy-agent-opa/&quot;&gt;https://sysdig.com/learn-cloud-native/what-is-an-open-policy-agent-opa/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Open Policy Agent (OPA) for Cloud Native Security - Styra, accessed on April 6, 2025, &lt;a href=&quot;https://www.styra.com/open-policy-agent/&quot;&gt;https://www.styra.com/open-policy-agent/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;5 Use Cases for Using Open Policy Agent - Jit.io, accessed on April 6, 2025, &lt;a href=&quot;https://www.jit.io/resources/security-standards/5-use-cases-for-using-open-policy-agent&quot;&gt;https://www.jit.io/resources/security-standards/5-use-cases-for-using-open-policy-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Understanding Open Policy Agent: A Simple Guide to OPA | by The kube guy | Medium, accessed on April 6, 2025, &lt;a href=&quot;https://thekubeguy.com/understanding-open-policy-agent-a-simple-guide-to-opa-77aff7ff9819&quot;&gt;https://thekubeguy.com/understanding-open-policy-agent-a-simple-guide-to-opa-77aff7ff9819&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform - Open Policy Agent, accessed on April 6, 2025, &lt;a href=&quot;https://www.openpolicyagent.org/docs/latest/terraform/&quot;&gt;https://www.openpolicyagent.org/docs/latest/terraform/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes with Open Policy Agent (OPA) &amp;amp; Gatekeeper - Spacelift, accessed on April 6, 2025, &lt;a href=&quot;https://spacelift.io/blog/opa-kubernetes&quot;&gt;https://spacelift.io/blog/opa-kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The challenges of using OPA for application authorization - Aserto, accessed on April 6, 2025, &lt;a href=&quot;https://www.aserto.com/blog/the-challenges-of-using-opa-for-application-authorization&quot;&gt;https://www.aserto.com/blog/the-challenges-of-using-opa-for-application-authorization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OPA Management: Challenges and Opportunities | Styra, accessed on April 6, 2025, &lt;a href=&quot;https://www.styra.com/blog/opa-management-challenges-and-opportunities/&quot;&gt;https://www.styra.com/blog/opa-management-challenges-and-opportunities/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Open Policy Agent Can Do THAT?! The Many Use Cases of OPA - YouTube, accessed on April 6, 2025, &lt;a href=&quot;https://www.youtube.com/watch?v=phvSK4pW1K8&quot;&gt;https://www.youtube.com/watch?v=phvSK4pW1K8&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Security</category><category>Cloud Governance</category><category>Policy as Code</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0072-policy-as-code-opa-guide/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Zero Trust Architecture in DevOps Pipelines: Secure Your CI/CD Workflows</title><link>https://mkabumattar.com/blog/post/zero-trust-devops-pipelines-securing-ci-cd/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/zero-trust-devops-pipelines-securing-ci-cd/</guid><description>Learn how to integrate Zero Trust Architecture into DevOps CI/CD pipelines using AWS, IAM, and micro-segmentation. Secure deployments without slowing innovation. Perfect for teams prioritizing speed and security.</description><pubDate>Sat, 05 Apr 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In today&amp;#39;s rapidly evolving digital landscape, security is paramount especially in DevOps environments where CI/CD pipelines and cloud infrastructure drive software delivery. One paradigm that’s reshaping our approach to security is &lt;strong&gt;Zero Trust&lt;/strong&gt;. This article explores Zero Trust in the context of DevOps pipelines, with a focus on practical AWS tools, IAM, VPC endpoints, and micro-segmentation strategies, all while ensuring that even complex security measures remain accessible and actionable.&lt;/p&gt;
&lt;h2&gt;What is Zero Trust and Why Should You Care?&lt;/h2&gt;
&lt;p&gt;Zero Trust is a security framework based on the principle: &lt;strong&gt;never trust, always verify&lt;/strong&gt;. Unlike traditional security models that rely on a secure perimeter, Zero Trust assumes that every request whether from inside or outside your network must be authenticated and authorized.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Zero Trust Matters in DevOps:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Environments:&lt;/strong&gt; Modern CI/CD pipelines and cloud infrastructures (like AWS) are dynamic. Zero Trust ensures every interaction is verified, no matter its origin.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced Security:&lt;/strong&gt; Through strict IAM policies and automated security rule checks, Zero Trust protects critical assets by limiting access to the minimum necessary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimized Risk:&lt;/strong&gt; Techniques such as micro-segmentation in AWS environments limit lateral movement, reducing the damage potential in case of breaches.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How Does Zero Trust Fit into CI/CD Pipelines?&lt;/h2&gt;
&lt;h3&gt;What Role Does Zero Trust Play in Your CI/CD Workflow?&lt;/h3&gt;
&lt;p&gt;CI/CD pipelines automate the process of code building, testing, and deployment. Without robust security, vulnerabilities may creep into production. Zero Trust addresses this by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Continuous Verification:&lt;/strong&gt; Every step in the CI/CD pipeline from code commit to deployment undergoes stringent verification, forming a series of Zero Trust security gates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Least Privilege:&lt;/strong&gt; Only essential permissions are granted. If an attacker compromises one segment, they won’t have unrestricted access.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated Security Checks:&lt;/strong&gt; Integrate automated scans and vulnerability assessments to catch issues before they escalate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By applying Zero Trust principles, your CI/CD pipeline becomes a fortress where every request is authenticated, ensuring that only trusted code is deployed.&lt;/p&gt;
&lt;h2&gt;How Can You Implement Zero Trust in Your DevOps Pipeline?&lt;/h2&gt;
&lt;h3&gt;What Are the Key Components for Zero Trust in DevOps?&lt;/h3&gt;
&lt;p&gt;Implementing Zero Trust involves a combination of tools, processes, and cultural shifts. Here’s how you can start:&lt;/p&gt;
&lt;h4&gt;1. &lt;strong&gt;AWS IAM for Granular Access Control&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Use AWS-native Zero Trust tools such as IAM to enforce the principle of least privilege. Every user and service should have only the access they need.&lt;/p&gt;
&lt;h4&gt;2. &lt;strong&gt;VPC Endpoints for Secure Connectivity&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Configure VPC endpoints to keep traffic between your VPC and AWS services private, ensuring data never traverses the public internet.&lt;/p&gt;
&lt;h4&gt;3. &lt;strong&gt;Micro-Segmentation in AWS Environments&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Think of micro-segmentation as locking each room in a house rather than just the front door. It restricts lateral movement, so even if one segment is compromised, others remain secure.&lt;/p&gt;
&lt;h4&gt;4. &lt;strong&gt;Automated Security Rule Checks in CI/CD Pipelines&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Integrate automated vulnerability scans (using tools like Snyk) into your pipeline to enforce continuous verification.&lt;/p&gt;
&lt;h4&gt;5. &lt;strong&gt;Zero Trust CI/CD Security Gates&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Incorporate security checks at each stage of the pipeline from code commit to deployment ensuring that any anomaly is caught early.&lt;/p&gt;
&lt;h2&gt;What Are the Benefits of Adopting Zero Trust in DevOps?&lt;/h2&gt;
&lt;h3&gt;How Does Zero Trust Enhance Security?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Granular Access Control:&lt;/strong&gt; Strict IAM policies ensure users and services have minimal access, reducing the potential attack surface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced Attack Surface:&lt;/strong&gt; VPC endpoints keep sensitive communications internal, shielding them from external threats.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Monitoring:&lt;/strong&gt; Automated security checks ensure vulnerabilities are detected and addressed quickly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adaptive Authentication:&lt;/strong&gt; Even if credentials are compromised, additional verification measures are in place.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Can Zero Trust Improve Efficiency?&lt;/h3&gt;
&lt;p&gt;Absolutely! Though adopting Zero Trust might seem complex initially, it streamlines your security processes over time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Faster Response Times:&lt;/strong&gt; Automated policies enable quick remediation of vulnerabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Developer Confidence:&lt;/strong&gt; With a secure pipeline, developers can focus on innovation rather than security concerns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced Compliance:&lt;/strong&gt; Zero Trust makes it easier to meet regulatory requirements by enforcing strict access controls and maintaining audit logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Frequently Asked Questions (FAQs)&lt;/h2&gt;
&lt;Accordion client:load title=&quot;Q1: What is Zero Trust in simple terms?&quot;&gt;&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Zero Trust means treating every request as untrusted until it’s verified, regardless of its origin. It’s about continuous validation rather than assuming any part of your network is safe.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Q2: How does Zero Trust integrate with DevOps?&quot;&gt;&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; In DevOps, Zero Trust is applied at every pipeline stage. It enforces strict access controls using tools like AWS IAM, secures communication with VPC endpoints, and uses micro-segmentation to limit lateral movement.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Q3: Is Zero Trust only applicable to cloud environments like AWS?&quot;&gt;&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; No. While AWS provides excellent native tools for Zero Trust, the principles can be applied in any environment cloud-based, on-premises, or hybrid.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Q4: What are some key AWS tools for Zero Trust?&quot;&gt;&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Key tools include AWS IAM for managing permissions, VPC endpoints for secure connectivity, and automated security scanning tools like Snyk for vulnerability assessment.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Q5: How does Zero Trust help prevent insider threats?&quot;&gt;&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; By enforcing the principle of least privilege and continuously verifying access, even insiders only get limited permissions, making unauthorized actions easier to detect.&lt;/p&gt;
&lt;/Accordion&gt;&lt;Accordion client:load title=&quot;Q6: How do I implement Zero Trust in legacy DevOps systems?&quot;&gt;&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Start by gradually refactoring pipelines to integrate Zero Trust principles. Use API gateways to manage access to legacy systems, and adopt hybrid solutions like AWS Outposts to extend modern security practices to older environments.&lt;/p&gt;
&lt;/Accordion&gt;&lt;h2&gt;Implementing Zero Trust in a CI/CD Pipeline: A Step-by-Step Guide&lt;/h2&gt;
&lt;h3&gt;Step 1: Assess Your Current Environment&lt;/h3&gt;
&lt;p&gt;Begin by reviewing your existing CI/CD processes and infrastructure. Identify critical assets, the flow of sensitive data, and current access control mechanisms. Look for potential gaps where implicit trust may be present.&lt;/p&gt;
&lt;h3&gt;Step 2: Define Your Security Policies&lt;/h3&gt;
&lt;p&gt;Establish clear security policies that align with Zero Trust principles. Decide on the minimum access rights for each role and define rules for how each component in your pipeline should interact.&lt;/p&gt;
&lt;h3&gt;Step 3: Configure AWS IAM&lt;/h3&gt;
&lt;p&gt;For cloud environments, configure IAM policies to ensure each user or service has only the access they need. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;Version&amp;quot;: &amp;quot;2012-10-17&amp;quot;,
  &amp;quot;Statement&amp;quot;: [
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: &amp;quot;s3:ListBucket&amp;quot;,
      &amp;quot;Resource&amp;quot;: &amp;quot;arn:aws:s3:::your-bucket&amp;quot;
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: &amp;quot;s3:GetObject&amp;quot;,
      &amp;quot;Resource&amp;quot;: &amp;quot;arn:aws:s3:::your-bucket/*&amp;quot;
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This JSON policy limits access to a specific S3 bucket and is an example of applying the principle of least privilege.&lt;/p&gt;
&lt;h3&gt;Step 4: Secure Network Communication with VPC Endpoints&lt;/h3&gt;
&lt;p&gt;Configure VPC endpoints to ensure that traffic between your AWS resources stays within your private network. This reduces exposure to the public internet, thereby enhancing security:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# AWS CLI command to create a VPC endpoint for S3
aws ec2 create-vpc-endpoint --vpc-id VPC_ID --service-name com.amazonaws.REGION.s3 --route-table-ids RTB_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 5: Enforce Micro-Segmentation&lt;/h3&gt;
&lt;p&gt;Segment your network to isolate critical services. Use tools like security groups, network ACLs, or service meshes to ensure that communication between different parts of your pipeline is tightly controlled.&lt;/p&gt;
&lt;h3&gt;Step 6: Integrate Automated Security Checks into CI/CD&lt;/h3&gt;
&lt;p&gt;Incorporate automated scanning tools into your CI/CD pipeline. For example, use a tool like Snyk or Aqua Security to scan your container images or code for vulnerabilities before deployment.&lt;/p&gt;
&lt;h3&gt;Step 7: Continuous Monitoring and Logging&lt;/h3&gt;
&lt;p&gt;Implement continuous monitoring to track access and usage patterns. Tools like AWS CloudTrail, Prometheus, and ELK stack can help you collect logs and detect anomalies, ensuring that every action is audited and verified.&lt;/p&gt;
&lt;h2&gt;Zero Trust Best Practices for DevOps Pipelines&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Least Privilege:&lt;/strong&gt; Always grant the minimum necessary permissions to every component in your pipeline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-Factor Authentication (MFA):&lt;/strong&gt; Require MFA for accessing critical systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated Policy Enforcement:&lt;/strong&gt; Use policy-as-code to automate the validation of your security configurations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regular Audits:&lt;/strong&gt; Perform periodic audits of IAM policies, network configurations, and access logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Training and Awareness:&lt;/strong&gt; Ensure that your team is aware of Zero Trust principles and follows secure practices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Real-World Case Study: Implementing Zero Trust in a CI/CD Pipeline&lt;/h2&gt;
&lt;p&gt;Imagine a mid-sized software company that deploys applications on AWS using a CI/CD pipeline. Initially, the company operated under the assumption that their internal network was secure. However, after experiencing a breach due to compromised credentials, they decided to implement a Zero Trust model.&lt;/p&gt;
&lt;h3&gt;The Challenge&lt;/h3&gt;
&lt;p&gt;The company had a complex pipeline with multiple teams contributing code. Access control was loosely enforced, and once inside the network, attackers could move laterally without much resistance.&lt;/p&gt;
&lt;h3&gt;The Solution&lt;/h3&gt;
&lt;p&gt;They implemented a Zero Trust architecture by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Revising IAM policies to enforce the least privilege.&lt;/li&gt;
&lt;li&gt;Setting up VPC endpoints to restrict external traffic.&lt;/li&gt;
&lt;li&gt;Segmenting their network using micro-segmentation techniques.&lt;/li&gt;
&lt;li&gt;Integrating automated security scans into their CI/CD pipeline.&lt;/li&gt;
&lt;li&gt;Implementing MFA and continuous monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Outcome&lt;/h3&gt;
&lt;p&gt;The result was a more secure, resilient, and auditable pipeline. The company saw a significant reduction in security incidents and increased confidence in their deployment process.&lt;/p&gt;
&lt;h2&gt;Avoid These Zero Trust Mistakes&lt;/h2&gt;
&lt;p&gt;Even with the best intentions, implementing Zero Trust can be challenging. Here are some common pitfalls and how to avoid them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Overcomplicating IAM Policies:&lt;/strong&gt; Start with broader policies and gradually refine them rather than attempting overly granular rules from the start.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ignoring Third-Party Integrations:&lt;/strong&gt; Extend Zero Trust principles to external tools by using API authentication and secure integration methods.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Neglecting Legacy Systems:&lt;/strong&gt; Integrate legacy systems gradually using API gateways and hybrid cloud solutions to avoid creating security gaps.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Zero Trust is more than a buzzword it&amp;#39;s a paradigm shift essential for securing modern DevOps pipelines. By applying Zero Trust principles to your CI/CD process using AWS IAM, VPC endpoints, and micro-segmentation, you can significantly reduce risk and enhance security. With continuous verification and automated security checks, your environment becomes more resilient against both external and internal threats.&lt;/p&gt;
&lt;p&gt;Start implementing Zero Trust today by assessing your current environment, defining strict security policies, and integrating these practices into your CI/CD pipelines. With the right tools and strategies, you can protect your cloud-native workflows and keep your organization secure.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;NIST Special Publication 800-207: Zero Trust Architecture.), &lt;a href=&quot;https://csrc.nist.gov/publications/detail/sp/800-207/final&quot;&gt;https://csrc.nist.gov/publications/detail/sp/800-207/final&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Well-Architected Framework - Security Pillar.), &lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/welcome.html&quot;&gt;https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Identity and Access Management (IAM) Best Practices.), &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html&quot;&gt;https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;VPC Endpoints and VPC Endpoint Services - Amazon Virtual Private Cloud.), &lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints.html&quot;&gt;https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Implementing Microsegmentation with AWS Network Firewall.), &lt;a href=&quot;https://aws.amazon.com/blogs/networking-and-content-delivery/implementing-microsegmentation-with-aws-network-firewall/&quot;&gt;https://aws.amazon.com/blogs/networking-and-content-delivery/implementing-microsegmentation-with-aws-network-firewall/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Securing CI/CD Pipelines - Cloud Security Alliance.), &lt;a href=&quot;https://cloudsecurityalliance.org/research/guidance/&quot;&gt;https://cloudsecurityalliance.org/research/guidance/&lt;/a&gt; (Note: Search for relevant CI/CD security documents on the CSA website)&lt;/li&gt;
&lt;li&gt;DevSecOps: Integrating Security into the DNA of Your DevOps Processes - SANS Institute.), &lt;a href=&quot;https://www.sans.org/white-papers/&quot;&gt;https://www.sans.org/white-papers/&lt;/a&gt; (Note: Search for relevant DevSecOps papers on the SANS website)&lt;/li&gt;
&lt;li&gt;Zero Trust for DevOps: A Practical Guide - (Example: Reputable Security Blog or Vendor Whitepaper, e.g., Palo Alto Networks, Zscaler, Okta.), [Link to a relevant resource]&lt;/li&gt;
&lt;li&gt;Automated Security Testing in CI/CD Pipelines - (Example: OWASP or a tool vendor like Snyk, Veracode.), [Link to a relevant resource]&lt;/li&gt;
&lt;li&gt;The Forrester Wave™: Zero Trust eXtended Ecosystem Platform Providers.), [Link to Forrester report summary if publicly available, or general Forrester site]&lt;/li&gt;
&lt;li&gt;Gartner: Market Guide for Zero Trust Network Access.), [Link to Gartner report summary if publicly available, or general Gartner site]&lt;/li&gt;
&lt;li&gt;Zero Trust Security Model - Microsoft Docs.), &lt;a href=&quot;https://docs.microsoft.com/en-us/security/zero-trust/&quot;&gt;https://docs.microsoft.com/en-us/security/zero-trust/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Cloud Security</category><category>Zero Trust Architecture</category><category>CI/CD</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0071-zero-trust-devops-pipelines-securing-ci-cd/hero.jpg" length="0" type="image/jpeg"/></item><item><title>VIM Cheat Sheet</title><link>https://mkabumattar.com/blog/post/vim-cheat-sheet/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/vim-cheat-sheet/</guid><description>VIM is a highly configurable, powerful text editor available on most Linux distributions. Ideal for editing files via the command line, its modal design offers distinct modes for various tasks. This cheat sheet provides a quick reference for VIM’s essential commands and features.</description><pubDate>Sat, 05 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;What Is VIM?&lt;/h2&gt;
&lt;p&gt;VIM (Vi Improved) is a versatile text editor pre-installed on most Linux systems, known for its efficiency in command-line file editing. Its modal nature switching between modes like Normal, Insert, and Command makes it a favorite among developers and system administrators. This cheat sheet serves as a handy guide to mastering VIM’s core functionalities.&lt;/p&gt;
&lt;h2&gt;VIM Modes&lt;/h2&gt;
&lt;p&gt;VIM operates in three primary modes, each designed for specific tasks, allowing users to navigate, edit, and manage files seamlessly.&lt;/p&gt;
&lt;h3&gt;Normal Mode&lt;/h3&gt;
&lt;p&gt;Normal Mode is VIM’s default state for navigation and manipulation. Use it to move the cursor, delete text, or copy content, entering it with the &lt;kbd class=&quot;btn-kdb&quot;&gt;Esc&lt;/kbd&gt; key.&lt;/p&gt;
&lt;h3&gt;Insert Mode&lt;/h3&gt;
&lt;p&gt;Insert Mode enables text input and editing. Activate it with the &lt;kbd class=&quot;btn-kdb&quot;&gt;i&lt;/kbd&gt; key to start typing at the cursor’s position.&lt;/p&gt;
&lt;h3&gt;Command Mode&lt;/h3&gt;
&lt;p&gt;Command Mode lets you execute file-level operations like saving or quitting. Access it by pressing &lt;kbd class=&quot;btn-kdb&quot;&gt;:&lt;/kbd&gt; from Normal Mode.&lt;/p&gt;
&lt;h2&gt;VIM Commands&lt;/h2&gt;
&lt;p&gt;This section lists essential VIM commands, organized by function, to streamline your workflow.&lt;/p&gt;
&lt;h3&gt;Global&lt;/h3&gt;
&lt;p&gt;Global commands affect the entire file or VIM environment, such as saving files or accessing help.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:h[elp] keyword&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open help for keyword.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:sav[eas] file&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Save the file as file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:clo[se]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Close the current file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:ter[minal]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a terminal.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;K&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open help for word under cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Cursor Movement&lt;/h3&gt;
&lt;p&gt;These commands control cursor navigation, helping you move efficiently within a file.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;h&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move left.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;j&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move down.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;k&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move up.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;l&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move right.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gj&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move down a screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gk&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move up a screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;H&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to top of screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;M&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to middle of screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;L&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to bottom of screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;w&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move forward one word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;W&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move forward one WORD.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;e&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to end of word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;E&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to end of WORD.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;b&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move back one word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;B&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move back one WORD.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ge&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to end of previous word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gE&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to end of previous WORD.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;%&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to matching character (default supported pairs: (), {}, []).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;0&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the start of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;^&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the first non-blank character of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;$&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the end of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;g_&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the last non-blank character of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gg&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the first line of the file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;G&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the last line of the file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;5G&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to line 5.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gd&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the definition of the word under the cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gD&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the definition of the WORD under the cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;fx&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the next occurrence of character x.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Fx&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the previous occurrence of character x.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;tx&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the character before the next occurrence of character x.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Tx&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the character after the previous occurrence of character x.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Repeat the previous f, t, F, or T movement.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;,&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Repeat the previous f, t, F, or T movement, but in the opposite direction.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the next paragraph (or function/block, when editing code).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the previous paragraph (or function/block, when editing code).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;zz&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Center cursor on screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;e&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move screen down one line (without moving cursor).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;y&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move screen up one line (without moving cursor).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;b&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move back one full screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;f&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move forward one full screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;d&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move forward half a screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;u&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move back half a screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Insert Mode&lt;/h3&gt;
&lt;p&gt;Insert Mode commands facilitate text entry and minor adjustments while typing.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;i&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Insert before the cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;I&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Insert at the beginning of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;a&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Insert (append) after the cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;A&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Insert (append) at the end of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;o&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Append (open) a new line below the current line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;O&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Append (open) a new line above the current line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ea&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Insert (append) at the end of the word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;h&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete the character before the cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;w&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete the word before the cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;j&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Begin a new line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;t&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift the current line one tab to the right.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;d&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift the current line one tab to the left.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;n&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Insert the next completion of the word under the cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;p&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Insert the previous completion of the word under the cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;rx&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Insert the register x contents.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;ox&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Temporarily enter Normal Mode to issue a single command.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ESC&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Exit Insert Mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Editing&lt;/h3&gt;
&lt;p&gt;Editing commands allow you to modify text, from single characters to entire lines.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;r&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Replace a single character.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;R&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Replace multiple characters.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;J&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Join line below to the current one with one space in between.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gJ&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Join line below to the current one without space in between.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gwip&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Reformat paragraph.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;g~&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Switch case of character under cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gu&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Make character under cursor lowercase.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gU&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Make character under cursor uppercase.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;cc&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Change (replace) an entire line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;c$&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Change (replace) to the end of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;C&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Change (replace) to the end of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ciw&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Change (replace) the entire word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;cw&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Change (replace) to the end of the word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ce&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Change (replace) to the end of the word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;s&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete character under cursor and substitute text.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;S&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete line and substitute text (same as cc).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;xp&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Transpose two letters (delete and paste).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;u&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Undo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;U&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Undo all changes on line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;r&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Redo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;.&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Repeat last command.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Marking Text (Visual Mode)&lt;/h3&gt;
&lt;p&gt;Visual Mode commands help you select text for further actions like copying or deleting.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;v&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Start Visual Mode, mark lines, then do a command (like y-yank).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;V&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Start linewise Visual Mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;o&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to other end of marked area.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;O&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to other corner of block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;v&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Start Visual Block Mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;aw&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Mark a word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ab&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;A block with ()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;aB&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;A block with {}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;at&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;A block with &amp;lt;&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ib&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Inner block with ()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;iB&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Inner block with {}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;it&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Inner block with &amp;lt;&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Esc&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Exit Visual Mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Visual Commands&lt;/h3&gt;
&lt;p&gt;These commands operate on text selected in Visual Mode, such as shifting or copying.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift text right.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;lt;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift text left.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;y&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank (copy) marked text.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;d&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete marked text.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;~&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Switch case.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;u&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Change marked text to lowercase.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;U&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Change marked text to uppercase.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Registers&lt;/h3&gt;
&lt;p&gt;Registers store text for later use, enhancing copy-paste efficiency.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:reg[isters]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;List all registers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&quot;xy&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank text into register x.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&quot;xp&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Paste text from register x.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&quot;xP&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Paste before cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&quot;+y&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank into system clipboard.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Marks and Positions&lt;/h3&gt;
&lt;p&gt;Marks and positions let you bookmark and jump to specific locations in a file.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:marks&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;List all marks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ma&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Set current position for mark a.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;a&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to mark a.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;y&apos;a&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank to mark a.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;0&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to start of line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&quot;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to last edit position.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;.&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to last edit position.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to last edit position.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:ju[mps]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;List all jump positions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;o&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to previous position.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;i&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to next position.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:changes&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;List all changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;g,&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to previous change.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;g;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to next change.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;j&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to next change.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Macros&lt;/h3&gt;
&lt;p&gt;Macros record and replay sequences of commands to automate repetitive tasks.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;qa&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Start recording macro a.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;q&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Stop recording macro.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;@a&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Execute macro a.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;@@&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Execute last macro.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Cut and Paste&lt;/h3&gt;
&lt;p&gt;Cut and paste commands handle copying, deleting, and moving text.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;yy&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank (copy) a line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;2yy&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank (copy) 2 lines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;yw&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank (copy) the characters of the word from the cursor position to the start of the next word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;y$&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank (copy) to end of line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;yiw&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank (copy) inner word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;yaw&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Yank (copy) a word including the surrounding white space.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;p&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Put (paste) the clipboard after cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;P&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Put (paste) before cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gp&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Put (paste) after cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gP&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Put (paste) before cursor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;dd&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete (cut) a line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;2dd&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete (cut) 2 lines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;dw&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete (cut) the characters of the word from the cursor position to the start of the next word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;D&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete (cut) to the end of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;d$&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete (cut) to the end of the line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;diw&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete (cut) inner word.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;daw&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete (cut) a word including the surrounding white space.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;x&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete (cut) character.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Indent Text&lt;/h3&gt;
&lt;p&gt;Indentation commands adjust text alignment, crucial for code formatting.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;gt;&amp;gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift text right.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;lt;&amp;lt;&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift text left.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;gt;%&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift selected lines right.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;lt;%&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift selected lines left.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;gt;ib&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift inner block right.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;lt;ib&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift inner block left.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;gt;at&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift block right.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;&amp;lt;at&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Shift block left.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;3==&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Auto indent 3 lines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;=%&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Auto indent selected lines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;=iB&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Auto indent inner block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gg=G&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Auto indent whole file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;]p&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Paste and indent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Exiting&lt;/h3&gt;
&lt;p&gt;Exiting commands manage how you save and close files in VIM.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:w&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Write (save) the file, but don&amp;#39;t exit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:w !sudo tee %&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Write out the current file using sudo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:wq&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Write (save) and quit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:x&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Write (save) and quit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ZZ&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Write (save) and quit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:q&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Quit (fails if there are unsaved changes).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:q!&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Quit and throw away unsaved changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;ZQ&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Quit and throw away unsaved changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:wqa&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Write (save) and quit on all tabs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:qa&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Quit on all tabs.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Search and Replace&lt;/h3&gt;
&lt;p&gt;Search and replace commands help you find and modify text efficiently.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;/pattern&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Search for pattern.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;?pattern&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Search backward for pattern.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;\vpattern&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Search for lines not containing pattern.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;n&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Repeat search in same direction.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;N&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Repeat search in opposite direction.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:%s/old/new/g&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Replace all old with new throughout file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:%s/old/new/gc&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Replace all old with new throughout file with confirmations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:s/old/new/g&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Replace all old with new in the current line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:s/old/new/gc&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Replace all old with new in the current line with confirmations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:noh[lsearch]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Remove highlighting of search matches.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Search in Multiple Files&lt;/h3&gt;
&lt;p&gt;These commands extend search capabilities across multiple files.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:vimgrep /pattern/ {file}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Search for pattern in multiple files.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:cn[ext]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to the next match.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:cp[revious]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Jump to the previous match.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:cope[n]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a window containing the list.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:ccl[ose]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Close the window.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Tabs&lt;/h3&gt;
&lt;p&gt;Tab commands manage multiple files in separate tabs for multitasking.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabe&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a new tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabnew {page.words.file}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a new tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gt&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the next tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabn[ext]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the next tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;gT&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the previous tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabp[revious]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the previous tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;#gt&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to tab #.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabm[ove] {number}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move the current tab to the {number}th position (indexed from 0).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabc[lose]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Close the current tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabo[nly]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Close all tabs except for the current one.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabr[ewind]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the first tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabfir[st]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the first tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabl[ast]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the last tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabs&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;List all tabs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabdo&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Run a command for each open tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabdo {cmd}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Run {cmd} for each open tab.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Working with Multiple Files&lt;/h3&gt;
&lt;p&gt;These commands handle multiple files using buffers and window splits.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Command&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:e[dit] {file}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Edit a file in a new buffer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:bn[ext]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Go to the next buffer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:bp[revious]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Go to the previous buffer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:bd[elete]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete a buffer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:b[uffer]{number}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Go to buffer {number}.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:b[uffer] file&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Go to buffer {file}.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:ls&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;List all open buffers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:buffers&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;List all open buffers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:sp[lit] {file}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a file in a new buffer and split window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:vsp[lit] {file}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a file in a new buffer and vertically split window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:vert[ical] ba[ll]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a file in a new buffer and vertically split window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tab ba[ll]&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a file in a new buffer and split window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabe[dit] {file}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a file in a new buffer and split window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tabnew {file}&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a file in a new buffer and split window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;:tab sball&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Open a file in a new buffer and split window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;ws&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Split window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;ww&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the next window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wq&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Close the current window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wv&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Split window vertically.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wh&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the window on the left.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wl&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the window on the right.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wj&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the window below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wk&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move to the window above.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;w=&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Make all windows the same height.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wH&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move the current window to the far left.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wL&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move the current window to the far right.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wJ&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move the current window to the bottom.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;kbd class=&quot;btn-kdb&quot;&gt;Ctrl&lt;/kbd&gt; + &lt;kbd class=&quot;btn-kdb&quot;&gt;wK&lt;/kbd&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Move the current window to the top.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;This guide covers VIM’s essentials: navigating files, editing text, performing search-and-replace operations, and managing multiple files. With practice, these commands will boost your productivity in this powerful editor.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vim.org/&quot;&gt;VIM Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vim.org/docs.php&quot;&gt;VIM Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vim-adventures.com/&quot;&gt;VIM Adventures (Interactive Tutorial)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.openvim.com/&quot;&gt;OpenVIM (Interactive Tutorial)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vim.rtorr.com/&quot;&gt;VIM Cheat Sheet by vim.rtorr.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://danielmiessler.com/p/vim/&quot;&gt;A VIM Tutorial and Primer by Daniel Miessler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freecodecamp.org/news/learn-vim-beginners-tutorial/&quot;&gt;Learn Vim (the Smart Way) - Free Code Camp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://vimdoc.sourceforge.net/htmldoc/usr_toc.html&quot;&gt;Vim User Manual by Bram Moolenaar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pragprog.com/titles/dnvim2/practical-vim-second-edition/&quot;&gt;Practical Vim: Edit Text at the Speed of Thought (Book by Drew Neil)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mhinz/vim-galore&quot;&gt;VIM Galore - A comprehensive guide to VIM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vim.fandom.com/wiki/Vim_Tips_Wiki&quot;&gt;VIM Wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thoughtbot.com/upcase/vim&quot;&gt;Thoughtbot - Learn Vim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://vimcasts.org/&quot;&gt;Vimcasts - Free Vim Screencasts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devhints.io/vim&quot;&gt;Devhints VIM Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linux.com/training-tutorials/vim-101-beginners-guide-vim/&quot;&gt;Linux.com - An Introduction to the VIM Editor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Linux</category><category>VIM</category><category>Text Editors</category><category>Developer Tools</category><category>Command Line</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0008-vim-cheat-sheet/hero.jpg" length="0" type="image/jpeg"/></item><item><title>10+ Secret Git Commands That Will Save Hours Every Week</title><link>https://mkabumattar.com/blog/post/10-secret-git-commands-to-save-time/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/10-secret-git-commands-to-save-time/</guid><description>Discover 10+ secret Git commands that will save hours every week! Learn advanced Git techniques for undoing mistakes, managing commits, automating workflows, and optimizing repositories. Perfect for DevOps and GitHub users.</description><pubDate>Sat, 22 Feb 2025 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;As a &lt;strong&gt;Software Engineer&lt;/strong&gt;, &lt;strong&gt;DevOps Engineer&lt;/strong&gt;, or &lt;strong&gt;GitHub user&lt;/strong&gt;, you probably use Git daily. But are you making the most of it? Git is packed with powerful commands that can save you &lt;strong&gt;hours of manual work&lt;/strong&gt; every week. In this guide, we&amp;#39;ll explore 10+ lesser-known but incredibly useful Git commands that will &lt;strong&gt;streamline your workflow&lt;/strong&gt;, improve &lt;strong&gt;automation&lt;/strong&gt;, and &lt;strong&gt;boost productivity&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Each command is grouped based on its use case, providing real-world scenarios so you can apply them immediately. Let’s dive in!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Undoing Changes Like a Pro&lt;/h2&gt;
&lt;h3&gt;1. &lt;code&gt;git reflog&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Recover lost commits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Tracks all actions performed in your repository, including resets and rebases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When you accidentally delete a branch or reset commits and need to recover them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Imagine you are working on a critical feature and accidentally run &lt;code&gt;git reset --hard&lt;/code&gt;, losing your latest commit. Instead of panicking, you can recover your work by running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git reflog
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Find the commit hash of the lost state and recover it with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git reset --hard &amp;lt;commit-hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now your work is back!&lt;/p&gt;
&lt;h3&gt;2. &lt;code&gt;git reset --soft HEAD~1&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Undo last commit but keep changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Removes the last commit but keeps the changes staged.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When you commit something too soon but don’t want to lose your changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; You just committed a file but realized you forgot to add an important change. Instead of creating another commit, you can undo the last commit while keeping your changes staged:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git reset --soft HEAD~1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now your changes are still staged, and you can amend them!&lt;/p&gt;
&lt;h3&gt;3. &lt;code&gt;git restore&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Revert modified files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Restores modified files to their last committed state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When you accidentally modify or delete files and need to revert them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; You mistakenly changed a config file and need to revert it to its last committed state. Instead of re-cloning the repo, you can simply run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git restore &amp;lt;filename&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your file is now back to its last committed version.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Managing Branches Efficiently&lt;/h2&gt;
&lt;h3&gt;4. &lt;code&gt;git switch&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Switch branches quickly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Quickly switches between branches.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When working on multiple features and need to jump between branches frequently.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; You are working on multiple features and need to switch between branches frequently. Instead of using &lt;code&gt;git checkout&lt;/code&gt; every time, you can use:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git switch feature-branch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Faster and cleaner than &lt;code&gt;git checkout&lt;/code&gt;!&lt;/p&gt;
&lt;h3&gt;5. &lt;code&gt;git worktree&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Work on multiple branches simultaneously.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Allows you to check out multiple branches in separate directories.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When working on multiple branches without switching context.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; You need to review a PR while working on a feature. Instead of stashing your changes, you can run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git worktree add ../review-pr feature-branch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you have both branches available in different directories!&lt;/p&gt;
&lt;h3&gt;6. &lt;code&gt;git rebase -i HEAD~&amp;lt;number-of-commits&amp;gt;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Clean up commit history.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Interactively rewrites commit history.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When cleaning up commit history before merging a branch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Your feature branch has 10 messy commits. Instead of merging them all, you can run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git rebase -i HEAD~10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pick, squash, or edit commits for a cleaner history!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Managing Commits Like a Boss&lt;/h2&gt;
&lt;h3&gt;7. &lt;code&gt;git cherry-pick&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Apply specific commits to another branch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Applies a specific commit to another branch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When you need to apply a hotfix from one branch to another.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; A bugfix commit exists in &lt;code&gt;dev&lt;/code&gt; but is needed in &lt;code&gt;main&lt;/code&gt;. Instead of merging everything, you can apply the specific commit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git cherry-pick &amp;lt;commit-hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8. &lt;code&gt;git commit --amend&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Modify the last commit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Modifies the last commit message or adds more changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When you make a small mistake in a commit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; You committed with the wrong message. Instead of creating a new commit, you can amend the last commit message:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git commit --amend -m &amp;quot;Corrected commit message&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No need for an extra commit!&lt;/p&gt;
&lt;h3&gt;9. &lt;code&gt;git range-diff&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Compare commit ranges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Compares two commit ranges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When reviewing a rebase before pushing changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Before force-pushing a rebased branch, you want to verify the changes. You can compare the commit ranges:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git range-diff origin/main HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures nothing important is lost.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Managing the Working Directory&lt;/h2&gt;
&lt;h3&gt;10. &lt;code&gt;git stash&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Save uncommitted changes temporarily.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Temporarily saves uncommitted changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When switching branches but keeping your work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; You need to check out &lt;code&gt;main&lt;/code&gt;, but have unfinished work. Instead of committing incomplete changes, you can stash them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git stash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Switch branches, then restore it with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git stash pop
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;11. &lt;code&gt;git sparse-checkout&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Checkout specific parts of a repository.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Allows checking out only specific parts of a repository.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When dealing with large monorepos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; You are working with a large monorepo and only need specific directories. Instead of cloning everything, you can initialize sparse-checkout:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git sparse-checkout init --cone
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then include specific folders:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git sparse-checkout set backend/
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Debugging and Auditing Code&lt;/h2&gt;
&lt;h3&gt;12. &lt;code&gt;git bisect&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Find the commit that introduced a bug.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Helps find which commit introduced a bug.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When debugging regressions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; A feature broke, but you don’t know when. You can automate the search for the bad commit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git bisect start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mark bad and good commits, and Git will find the culprit!&lt;/p&gt;
&lt;h3&gt;13. &lt;code&gt;git blame&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Identify who modified each line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Shows who last modified each line in a file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When investigating why a piece of code changed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; You found a bug in a file and want to know who last modified it. You can run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git blame config.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you know whom to ask!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By mastering these Git commands, you can &lt;strong&gt;save hours every week&lt;/strong&gt;, work more efficiently in &lt;strong&gt;Git&lt;/strong&gt;, and &lt;strong&gt;streamline your workflow&lt;/strong&gt;. Whether you are a &lt;strong&gt;Software Engineer&lt;/strong&gt;, &lt;strong&gt;DevOps Engineer&lt;/strong&gt;, or &lt;strong&gt;GitHub user&lt;/strong&gt;, these commands will help you &lt;strong&gt;undo changes&lt;/strong&gt;, &lt;strong&gt;manage branches&lt;/strong&gt;, &lt;strong&gt;optimize commits&lt;/strong&gt;, and &lt;strong&gt;debug code&lt;/strong&gt; like a pro.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Pro Git book - Scott Chacon and Ben Straub.), &lt;a href=&quot;https://git-scm.com/book/en/v2&quot;&gt;https://git-scm.com/book/en/v2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Git Documentation - Official Git SCM.), &lt;a href=&quot;https://git-scm.com/doc&quot;&gt;https://git-scm.com/doc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Atlassian Git Tutorial.), &lt;a href=&quot;https://www.atlassian.com/git/tutorials&quot;&gt;https://www.atlassian.com/git/tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git reflog&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-reflog&quot;&gt;https://git-scm.com/docs/git-reflog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git reset&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-reset&quot;&gt;https://git-scm.com/docs/git-reset&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git restore&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-restore&quot;&gt;https://git-scm.com/docs/git-restore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git switch&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-switch&quot;&gt;https://git-scm.com/docs/git-switch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git worktree&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-worktree&quot;&gt;https://git-scm.com/docs/git-worktree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git rebase&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-rebase&quot;&gt;https://git-scm.com/docs/git-rebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git cherry-pick&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-cherry-pick&quot;&gt;https://git-scm.com/docs/git-cherry-pick&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-stash&quot;&gt;https://git-scm.com/docs/git-stash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git sparse-checkout&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-sparse-checkout&quot;&gt;https://git-scm.com/docs/git-sparse-checkout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git bisect&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-bisect&quot;&gt;https://git-scm.com/docs/git-bisect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git blame&lt;/code&gt; - Git SCM.), &lt;a href=&quot;https://git-scm.com/docs/git-blame&quot;&gt;https://git-scm.com/docs/git-blame&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub Guides.), &lt;a href=&quot;https://guides.github.com/&quot;&gt;https://guides.github.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Git</category><category>Version Control</category><category>DevOps</category><category>Software Development</category><category>Productivity</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0070-10-secret-git-commands-to-save-time/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Streamlining GitHub Organization Management with Terraform</title><link>https://mkabumattar.com/blog/post/streamlining-github-organization-management-with-terraform/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/streamlining-github-organization-management-with-terraform/</guid><description>Learn how to manage a large GitHub organization efficiently using Terraform. Discover key Terraform resources for automating user access, team structures, and repository configurations.</description><pubDate>Sat, 11 Jan 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Managing a GitHub organization manually can become increasingly complex as teams grow and projects multiply. For DevOps and DevSecOps engineers, &lt;strong&gt;automation&lt;/strong&gt; is key to maintaining consistency and reducing human error. That&amp;#39;s where &lt;strong&gt;Terraform&lt;/strong&gt;, a popular Infrastructure as Code (IaC) tool, comes into play. By leveraging Terraform, you can automate and streamline the management of your GitHub organization, from user access to team structures and repository configurations. This article explores how Terraform simplifies GitHub organization management, with real-world examples to illustrate its power.&lt;/p&gt;
&lt;h2&gt;What Is Terraform and Why Use It for GitHub Organization Management?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Terraform&lt;/strong&gt; is an open-source IaC tool that allows you to define and manage infrastructure in a declarative configuration language. Traditionally used for cloud resources like AWS or Azure, Terraform also has providers for various platforms, including &lt;strong&gt;GitHub&lt;/strong&gt;. By using the GitHub provider, you can automate the management of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repositories&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Teams&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Team memberships&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User permissions&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach aligns with DevOps principles by ensuring that infrastructure configurations, including your GitHub organization setup, are version-controlled, auditable, and reproducible.&lt;/p&gt;
&lt;h2&gt;Why Automate GitHub Organization Management?&lt;/h2&gt;
&lt;p&gt;Automation reduces manual intervention, which:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensures consistency across environments&lt;/li&gt;
&lt;li&gt;Improves security and compliance&lt;/li&gt;
&lt;li&gt;Minimizes the risk of human error&lt;/li&gt;
&lt;li&gt;Speeds up onboarding and offboarding processes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By automating these tasks, you free up time for more strategic activities.&lt;/p&gt;
&lt;h2&gt;Key Terraform Resources for GitHub Management&lt;/h2&gt;
&lt;p&gt;Let’s dive into some of the critical Terraform resources for managing a GitHub organization, along with detailed scenarios and examples.&lt;/p&gt;
&lt;h3&gt;1. &lt;code&gt;github_membership&lt;/code&gt;: Managing Organization Members&lt;/h3&gt;
&lt;p&gt;This resource manages whether a user is a member or an owner of a GitHub organization. It&amp;#39;s useful for automating user onboarding and ensuring appropriate access levels.&lt;/p&gt;
&lt;h4&gt;Scenario: Automating Onboarding for New Engineers&lt;/h4&gt;
&lt;p&gt;Your team has onboarded a new engineer, Jane, who needs access to the organization as a member. Traditionally, you would manually add her, but Terraform can automate this process:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;resource &amp;quot;github_membership&amp;quot; &amp;quot;jane_membership&amp;quot; {
  username = &amp;quot;jane-doe&amp;quot;
  role     = &amp;quot;member&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By applying this configuration, Jane is added as a member, ensuring consistency and saving time.&lt;/p&gt;
&lt;h3&gt;2. &lt;code&gt;github_team_membership&lt;/code&gt;: Assigning Users to Teams&lt;/h3&gt;
&lt;p&gt;This resource allows you to manage which users belong to specific teams within your organization.&lt;/p&gt;
&lt;h4&gt;Scenario: Adding Developers to Specialized Teams&lt;/h4&gt;
&lt;p&gt;Jane needs to be added to the &lt;strong&gt;backend-team&lt;/strong&gt;. Here’s how you can achieve this with Terraform:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;resource &amp;quot;github_team&amp;quot; &amp;quot;backend_team&amp;quot; {
  name        = &amp;quot;backend-team&amp;quot;
  description = &amp;quot;Team responsible for backend services.&amp;quot;
}

resource &amp;quot;github_team_membership&amp;quot; &amp;quot;jane_backend&amp;quot; {
  team_id  = github_team.backend_team.id
  username = &amp;quot;jane-doe&amp;quot;
  role     = &amp;quot;member&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures that Jane gains immediate access to the repositories and workflows tied to the backend team.&lt;/p&gt;
&lt;h3&gt;3. &lt;code&gt;github_repository&lt;/code&gt;: Creating and Configuring Repositories&lt;/h3&gt;
&lt;p&gt;This resource manages the creation and configuration of GitHub repositories.&lt;/p&gt;
&lt;h4&gt;Scenario: Launching a New Microservice&lt;/h4&gt;
&lt;p&gt;Your team is tasked with developing a new microservice called &lt;strong&gt;order-service&lt;/strong&gt;. With Terraform, you can automate repository creation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;resource &amp;quot;github_repository&amp;quot; &amp;quot;order_service&amp;quot; {
  name        = &amp;quot;order-service&amp;quot;
  description = &amp;quot;Handles order processing and management.&amp;quot;
  visibility  = &amp;quot;private&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration ensures consistent repository settings and reduces setup time.&lt;/p&gt;
&lt;h3&gt;4. &lt;code&gt;github_team_repository&lt;/code&gt;: Managing Team Access to Repositories&lt;/h3&gt;
&lt;p&gt;This resource links teams to repositories and defines their access levels.&lt;/p&gt;
&lt;h4&gt;Scenario: Granting Backend Team Access to the Order Service Repository&lt;/h4&gt;
&lt;p&gt;To give the backend team access to the &lt;strong&gt;order-service&lt;/strong&gt; repository, use the following configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;resource &amp;quot;github_team_repository&amp;quot; &amp;quot;backend_order_access&amp;quot; {
  team_id    = github_team.backend_team.id
  repository = github_repository.order_service.name
  permission = &amp;quot;push&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures that the backend team has the necessary permissions to contribute to the repository.&lt;/p&gt;
&lt;h3&gt;5. &lt;code&gt;github_branch_protection&lt;/code&gt;: Enforcing Branch Protection Rules&lt;/h3&gt;
&lt;p&gt;This resource manages branch protection rules to enforce policies on specific branches.&lt;/p&gt;
&lt;h4&gt;Scenario: Enforcing Branch Protection on the Main Branch&lt;/h4&gt;
&lt;p&gt;To protect the &lt;code&gt;main&lt;/code&gt; branch of the &lt;strong&gt;order-service&lt;/strong&gt; repository, you can configure branch protection as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;resource &amp;quot;github_branch_protection&amp;quot; &amp;quot;main_branch_protection&amp;quot; {
  repository_id = github_repository.order_service.name
  pattern       = &amp;quot;main&amp;quot;

  required_status_checks {
    strict   = true
    contexts = [&amp;quot;ci/circleci&amp;quot;]
  }

  enforce_admins = true
  required_pull_request_reviews {
    dismiss_stale_reviews           = true
    require_code_owner_reviews      = true
    required_approving_review_count = 2
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures that changes to the &lt;code&gt;main&lt;/code&gt; branch undergo rigorous review before being merged.&lt;/p&gt;
&lt;h3&gt;Using GitHub PRs and the &lt;code&gt;CODEOWNERS&lt;/code&gt; Feature for an Approval Flow&lt;/h3&gt;
&lt;p&gt;Enhance your GitHub management workflow by combining the &lt;strong&gt;Pull Request (PR) process&lt;/strong&gt; with the &lt;strong&gt;&lt;code&gt;CODEOWNERS&lt;/code&gt;&lt;/strong&gt; file. The &lt;code&gt;CODEOWNERS&lt;/code&gt; file specifies which team members must approve changes to specific parts of a repository.&lt;/p&gt;
&lt;h4&gt;Scenario: Requiring Backend Team Approval for Critical Code&lt;/h4&gt;
&lt;p&gt;Define a &lt;code&gt;CODEOWNERS&lt;/code&gt; file to require backend team approval for changes in the &lt;code&gt;src/backend/&lt;/code&gt; directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;# CODEOWNERS file
src/backend/ @backend-team
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup ensures that any changes to the &lt;code&gt;src/backend/&lt;/code&gt; directory are automatically flagged for review by the &lt;code&gt;@backend-team&lt;/code&gt;, enhancing code quality and security.&lt;/p&gt;
&lt;h2&gt;How to Get Started with Terraform for GitHub&lt;/h2&gt;
&lt;h3&gt;Step 1: Install Terraform&lt;/h3&gt;
&lt;p&gt;First, you need to install Terraform on your machine. You can download it from the &lt;a href=&quot;https://www.terraform.io/downloads.html&quot;&gt;official Terraform website&lt;/a&gt;. Follow the installation instructions for your operating system.&lt;/p&gt;
&lt;h3&gt;Step 2: Configure the GitHub Provider&lt;/h3&gt;
&lt;p&gt;Next, you need to configure the GitHub provider. Create a new directory for your Terraform configuration files and navigate to it. Then, create a &lt;code&gt;main.tf&lt;/code&gt; file and add the following configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;provider &amp;quot;github&amp;quot; {
  token = &amp;quot;your_github_token&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;quot;your_github_token&amp;quot;&lt;/code&gt; with a personal access token from GitHub. You can generate a token by going to your GitHub account settings, navigating to &amp;quot;Developer settings&amp;quot; &amp;gt; &amp;quot;Personal access tokens,&amp;quot; and creating a new token with the necessary scopes (e.g., &lt;code&gt;repo&lt;/code&gt;, &lt;code&gt;admin:org&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;Step 3: Define Your Resources&lt;/h3&gt;
&lt;p&gt;Write your Terraform configurations using the resources covered in this article. For example, to manage organization members, teams, and repositories, you can add the following configurations to your &lt;code&gt;main.tf&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-terraform&quot;&gt;resource &amp;quot;github_membership&amp;quot; &amp;quot;jane_membership&amp;quot; {
  username = &amp;quot;jane-doe&amp;quot;
  role     = &amp;quot;member&amp;quot;
}

resource &amp;quot;github_team&amp;quot; &amp;quot;backend_team&amp;quot; {
  name        = &amp;quot;backend-team&amp;quot;
  description = &amp;quot;Team responsible for backend services.&amp;quot;
}

resource &amp;quot;github_team_membership&amp;quot; &amp;quot;jane_backend&amp;quot; {
  team_id  = github_team.backend_team.id
  username = &amp;quot;jane-doe&amp;quot;
  role     = &amp;quot;member&amp;quot;
}

resource &amp;quot;github_repository&amp;quot; &amp;quot;order_service&amp;quot; {
  name        = &amp;quot;order-service&amp;quot;
  description = &amp;quot;Handles order processing and management.&amp;quot;
  visibility  = &amp;quot;private&amp;quot;
}

resource &amp;quot;github_team_repository&amp;quot; &amp;quot;backend_order_access&amp;quot; {
  team_id    = github_team.backend_team.id
  repository = github_repository.order_service.name
  permission = &amp;quot;push&amp;quot;
}

resource &amp;quot;github_branch_protection&amp;quot; &amp;quot;main_branch_protection&amp;quot; {
  repository_id = github_repository.order_service.name
  pattern       = &amp;quot;main&amp;quot;

  required_status_checks {
    strict   = true
    contexts = [&amp;quot;ci/circleci&amp;quot;]
  }

  enforce_admins = true
  required_pull_request_reviews {
    dismiss_stale_reviews           = true
    require_code_owner_reviews      = true
    required_approving_review_count = 2
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Initialize Terraform&lt;/h3&gt;
&lt;p&gt;Before applying your configuration, you need to initialize Terraform. This step downloads the necessary provider plugins and prepares your working directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;terraform init
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 5: Plan and Apply the Configuration&lt;/h3&gt;
&lt;p&gt;Run the following commands to see a preview of the changes Terraform will make and then apply those changes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;terraform plan
terraform apply
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;plan&lt;/code&gt; command shows you the actions Terraform will take without making any changes. The &lt;code&gt;apply&lt;/code&gt; command applies the changes to your GitHub organization.&lt;/p&gt;
&lt;h3&gt;Step 6: Verify the Changes&lt;/h3&gt;
&lt;p&gt;After applying the configuration, verify that the changes have been made in your GitHub organization. Check that the new members, teams, repositories, and branch protection rules have been created as expected.&lt;/p&gt;
&lt;h3&gt;Step 7: Manage State&lt;/h3&gt;
&lt;p&gt;Terraform keeps track of your infrastructure&amp;#39;s state in a file called &lt;code&gt;terraform.tfstate&lt;/code&gt;. This file is crucial for managing your resources. Make sure to store it securely and consider using a remote backend (e.g., AWS S3, Terraform Cloud) for better collaboration and state management.&lt;/p&gt;
&lt;h3&gt;Step 8: Update and Destroy Resources&lt;/h3&gt;
&lt;p&gt;To update your resources, modify your &lt;code&gt;.tf&lt;/code&gt; files and run &lt;code&gt;terraform plan&lt;/code&gt; and &lt;code&gt;terraform apply&lt;/code&gt; again. To destroy the resources managed by Terraform, run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;terraform destroy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command removes all the resources defined in your configuration.&lt;/p&gt;
&lt;p&gt;By following these steps, you can efficiently manage your GitHub organization using Terraform, ensuring consistency, security, and scalability.&lt;/p&gt;
&lt;h2&gt;Pros and Cons of Using Terraform for GitHub Management&lt;/h2&gt;
&lt;h3&gt;Pros:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Automation&lt;/strong&gt;: Saves time and ensures consistency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version Control&lt;/strong&gt;: Tracks changes to your GitHub organization setup.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Easily manage large organizations with multiple teams and repositories.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Reduces human error and enforces compliance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Cons:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;: Requires knowledge of Terraform and HCL.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Initial Setup Effort&lt;/strong&gt;: Setting up configurations can take time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limited Real-Time Feedback&lt;/strong&gt;: Debugging issues can be slower than manual updates.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Using Terraform to manage your GitHub organization is a smart move for DevOps and DevSecOps engineers aiming to streamline workflows, enhance security, and ensure consistency. Whether you’re managing team memberships, repository settings, or user roles, Terraform provides a scalable and auditable solution.&lt;/p&gt;
&lt;p&gt;By adopting Infrastructure as Code for GitHub management, you align your practices with modern DevOps principles, setting the stage for smoother, more efficient operations.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Terraform GitHub Provider Documentation.), &lt;a href=&quot;https://registry.terraform.io/providers/integrations/github/latest/docs&quot;&gt;https://registry.terraform.io/providers/integrations/github/latest/docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Managing GitHub with Terraform - HashiCorp Learn.), &lt;a href=&quot;https://learn.hashicorp.com/tutorials/terraform/github-actions&quot;&gt;https://learn.hashicorp.com/tutorials/terraform/github-actions&lt;/a&gt; (Note: While this link mentions GitHub Actions, HashiCorp Learn often has broader GitHub management tutorials.)&lt;/li&gt;
&lt;li&gt;Official Terraform Documentation.), &lt;a href=&quot;https://www.terraform.io/docs/index.html&quot;&gt;https://www.terraform.io/docs/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub Help: Managing organization security.), &lt;a href=&quot;https://docs.github.com/en/organizations/keeping-your-organization-secure&quot;&gt;https://docs.github.com/en/organizations/keeping-your-organization-secure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub Help: About CODEOWNERS.), &lt;a href=&quot;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners&quot;&gt;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Infrastructure as Code: A Guide by HashiCorp.), &lt;a href=&quot;https://www.hashicorp.com/resources/what-is-infrastructure-as-code&quot;&gt;https://www.hashicorp.com/resources/what-is-infrastructure-as-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Automating GitHub Organization Management with Terraform - (Example: Blog post from a reputable tech blog like Medium, DEV.to, or a company blog.), [Link to a relevant blog post]&lt;/li&gt;
&lt;li&gt;Terraform Best Practices for GitHub Management - (Example: Community forums or best practice guides.), [Link to a relevant guide]&lt;/li&gt;
&lt;li&gt;&lt;code&gt;github_membership&lt;/code&gt; resource - Terraform Registry.), &lt;a href=&quot;https://registry.terraform.io/providers/integrations/github/latest/docs/resources/membership&quot;&gt;https://registry.terraform.io/providers/integrations/github/latest/docs/resources/membership&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;github_team_repository&lt;/code&gt; resource - Terraform Registry.), &lt;a href=&quot;https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team_repository&quot;&gt;https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team_repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;github_branch_protection&lt;/code&gt; resource - Terraform Registry.), &lt;a href=&quot;https://registry.terraform.io/providers/integrations/github/latest/docs/resources/branch_protection&quot;&gt;https://registry.terraform.io/providers/integrations/github/latest/docs/resources/branch_protection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using Terraform to Manage GitHub Teams and Permissions - (Example: Another relevant tutorial or blog post.), [Link to a relevant resource]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Infrastructure as Code</category><category>GitHub</category><category>Automation</category><category>Terraform</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0069-streamlining-github-organization-management-with-terraform/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Getting Addicted to Coding: Why We Love Programming More Than Sleep</title><link>https://mkabumattar.com/blog/post/getting-addicted-to-coding/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/getting-addicted-to-coding/</guid><description>Discover why programming is so addicting and how to maintain a healthy balance while pursuing your passion for coding. Learn about the thrill of problem-solving, instant feedback, and tips to avoid burnout.</description><pubDate>Fri, 15 Nov 2024 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Coding is not just a skill; for many, it becomes a passion, a lifestyle, and sometimes, an obsession. But what makes programming so captivating? Why do some developers lose track of time while coding, skipping meals and sacrificing sleep? Is this passion for programming healthy, or can it become an addiction? Let’s dive into these questions and uncover why getting &amp;quot;addicted&amp;quot; to coding is more common than you think.&lt;/p&gt;
&lt;h2&gt;Why Is Programming So Addicting?&lt;/h2&gt;
&lt;p&gt;Programming combines creativity, problem-solving, and instant gratification in a way that few other activities do. Here’s why it’s so addictive:&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;The Thrill of Problem-Solving&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;At its core, coding is about solving problems. When you crack a challenging algorithm or fix a pesky bug, your brain gets a hit of dopamine, the same chemical that makes other addictive behaviors rewarding. It feels like completing a puzzle, only amplified because your solution often has real-world impact.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Think about debugging. Hours of frustration are instantly replaced by euphoria when you finally squash that bug and your program works as expected.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Immediate Feedback&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Coding provides instant feedback. Write a line of code, run it, and you immediately see the results. This rapid cycle of input and output keeps your brain engaged and craving more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Unlike tasks that take days or weeks to show results, programming lets you see progress in minutes, making it hard to put down.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Endless Learning Opportunities&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The tech world evolves at breakneck speed, offering developers endless new languages, frameworks, and tools to explore. This constant learning keeps programming fresh and exciting, fueling curiosity and passion.&lt;/p&gt;
&lt;h2&gt;Can Coding Be an Addiction?&lt;/h2&gt;
&lt;p&gt;Yes, coding can become an addiction not in the clinical sense, but in a way that consumes your time, focus, and energy. Here’s what to watch out for:&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Signs of Over-Engagement&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Skipping meals or sleep to code.&lt;/li&gt;
&lt;li&gt;Neglecting other responsibilities or hobbies.&lt;/li&gt;
&lt;li&gt;Constantly thinking about coding, even during downtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While passion for programming is natural, these signs may indicate an imbalance that could lead to burnout.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Healthy Passion vs. Obsession&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Loving what you do is fantastic, but it’s essential to maintain boundaries. Overworking, even on something you love, can harm your mental and physical health. A healthy approach to coding involves breaks, exercise, and social interaction.&lt;/p&gt;
&lt;h2&gt;Why Am I Interested in Coding?&lt;/h2&gt;
&lt;p&gt;Your interest in coding likely stems from its unique blend of logic and creativity. Here’s why coding might resonate with you:&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Creative Outlet&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Coding allows you to build something from nothing, whether it’s a personal website, a mobile app, or a data visualization. The ability to create functional, beautiful tools is incredibly satisfying.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Logical Structure&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For those who enjoy logical thinking and structured tasks, coding feels like second nature. It’s a skill that rewards systematic problem-solving and clear thinking.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Tangible Impact&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The apps, websites, and systems we interact with daily are built by developers. Knowing your work can impact others’ lives adds meaning and purpose to coding.&lt;/p&gt;
&lt;h2&gt;Why Do Some People Enjoy Coding?&lt;/h2&gt;
&lt;p&gt;Not everyone finds joy in writing code, but for those who do, it’s often because of these factors:&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Empowerment Through Knowledge&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Coding gives you the tools to solve problems, automate tasks, and create new technologies. This empowerment is a big reason why people fall in love with programming.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;The Developer Community&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Programming isn’t just a solo activity. The global developer community is incredibly supportive, offering forums, open-source projects, and meetups where coders can collaborate and share knowledge.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Platforms like GitHub and Stack Overflow foster a sense of belonging and mutual growth among developers.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Career and Financial Rewards&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Let’s face it: programming is a lucrative skill. For many, the financial and career opportunities make coding even more enjoyable, turning it into a life-changing profession.&lt;/p&gt;
&lt;h2&gt;Balancing Passion with Life&lt;/h2&gt;
&lt;p&gt;If you’re passionate about coding, that’s amazing! But remember, balance is key to long-term success. Here are tips to keep your passion healthy:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Set Time Limits:&lt;/strong&gt; Allocate specific hours for coding to avoid burnout.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Take Breaks:&lt;/strong&gt; Use techniques like the Pomodoro method to stay fresh.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stay Active:&lt;/strong&gt; Physical exercise and mental downtime are essential.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Socialize:&lt;/strong&gt; Connect with others, both inside and outside the tech community.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reflect:&lt;/strong&gt; Regularly assess whether your coding habits align with your life goals.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&amp;quot;The Psychology of Programming&amp;quot; by Gerald M. Weinberg.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Why Is Coding So Addictive?&amp;quot; - (Example: Article from a tech blog like freeCodeCamp, DEV.to, or Psychology Today.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Understanding and Preventing Developer Burnout&amp;quot; - (Example: Article from Atlassian, Stack Overflow Blog, or a health-focused tech site.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;The Dopamine Loop: Why We&amp;#39;re Addicted to Tech&amp;quot; - (Example: Article from a science or psychology publication.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Finding Flow: The Psychology of Optimal Experience&amp;quot; by Mihaly Csikszentmihalyi.), [Link to a reputable source for the book or summary, as it relates to deep work in coding]&lt;/li&gt;
&lt;li&gt;&amp;quot;Healthy Habits for Programmers&amp;quot; - (Example: Guide from a developer community or health organization.), [Link to a relevant guide]&lt;/li&gt;
&lt;li&gt;&amp;quot;The Importance of Hobbies for Developers&amp;quot; - (Example: Blog post discussing work-life balance for tech professionals.), [Link to a relevant blog post]&lt;/li&gt;
&lt;li&gt;&amp;quot;How to Avoid Burnout When You&amp;#39;re Passionate About Your Work&amp;quot; - (Example: Article from Harvard Business Review or similar.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;The Role of Community in Developer Well-being&amp;quot; - (Example: Discussion on platforms like GitHub or Stack Overflow, or an article about tech communities.), [Link to a relevant resource]&lt;/li&gt;
&lt;li&gt;&amp;quot;Setting Boundaries: Work-Life Balance for Remote Developers&amp;quot; - (Example: Article focusing on remote work challenges and solutions.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Cognitive Biases in Software Development&amp;quot; - (Example: Article exploring how our thinking can affect coding habits, potentially leading to overwork.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;The Joy of Coding: Why People Love to Program&amp;quot; - (Example: Inspirational articles or talks about the positive aspects of programming.), [Link to a relevant resource]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Programming</category><category>Career Development</category><category>Developer Lifestyle</category><category>Mental Health</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0068-getting-addicted-to-coding/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Deploying Infrastructure with Terraform in CI/CD Pipelines</title><link>https://mkabumattar.com/blog/post/deploying-infrastructure-with-terraform-in-ci-cd-pipelines/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/deploying-infrastructure-with-terraform-in-ci-cd-pipelines/</guid><description>Learn how to deploy infrastructure using Terraform in a CI/CD pipeline. Discover how Terraform fits into DevOps workflows and how to create a CI/CD pipeline with GitHub Actions for Terraform automation.</description><pubDate>Sun, 22 Sep 2024 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In today’s fast-paced DevOps environments, Infrastructure as Code (IaC) has become a cornerstone for managing and scaling infrastructure efficiently. &lt;strong&gt;Terraform&lt;/strong&gt;, a leading open-source IaC tool, is widely adopted for its ability to automate infrastructure deployment across multiple cloud platforms. However, there’s often a question: &lt;em&gt;What’s the best way to deploy Terraform configurations using CI/CD pipelines?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This blog will explore how Terraform fits into CI/CD workflows, how to deploy infrastructure using CI/CD pipelines, and answer key questions about integrating Terraform into your DevOps practices.&lt;/p&gt;
&lt;h2&gt;Is Terraform Good for CI/CD?&lt;/h2&gt;
&lt;p&gt;Absolutely, &lt;strong&gt;Terraform&lt;/strong&gt; is an excellent tool for CI/CD pipelines because it allows teams to automate the entire infrastructure deployment lifecycle. It integrates seamlessly with various CI/CD tools and provides robust, reusable infrastructure modules.&lt;/p&gt;
&lt;p&gt;The primary benefit of using Terraform in CI/CD pipelines is &lt;strong&gt;automation&lt;/strong&gt;. Whether you’re managing a multi-cloud environment or a single platform, Terraform ensures your infrastructure is consistent, repeatable, and version-controlled.&lt;/p&gt;
&lt;h3&gt;Benefits of Terraform in CI/CD&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consistency:&lt;/strong&gt; Every infrastructure change is recorded and can be repeated with precision.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; Terraform supports large-scale deployments, making it perfect for cloud-native architectures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexibility:&lt;/strong&gt; It works across different cloud platforms (AWS, Azure, GCP), which means you don&amp;#39;t have to depend on provider-specific tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaboration:&lt;/strong&gt; By storing your infrastructure code in Git repositories, teams can collaborate, review, and approve infrastructure changes through pull requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;FAQ:&lt;/strong&gt; &lt;em&gt;Why is Terraform particularly well-suited for CI/CD?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Terraform’s declarative syntax allows you to define your infrastructure, much like application code. When integrated with CI/CD pipelines, this makes it possible to deploy changes, enforce policy checks, and ensure compliance in a fully automated way.&lt;/p&gt;
&lt;h2&gt;How Do You Deploy Your Infrastructure in CI/CD Using Terraform?&lt;/h2&gt;
&lt;p&gt;Terraform’s design philosophy makes it relatively simple to deploy infrastructure using any CI/CD system. Here’s a general approach to how you can do this:&lt;/p&gt;
&lt;h3&gt;Step 1: Write Your Terraform Code&lt;/h3&gt;
&lt;p&gt;Begin by writing the Terraform code that describes the infrastructure. Whether it&amp;#39;s provisioning servers, databases, or networking components, you define the desired state of your environment.&lt;/p&gt;
&lt;h3&gt;Step 2: Store Your Code in Version Control&lt;/h3&gt;
&lt;p&gt;Next, store your Terraform configurations in a version control system like GitHub or GitLab. This enables collaboration and ensures that changes to the infrastructure are reviewed and approved through pull requests.&lt;/p&gt;
&lt;h3&gt;Step 3: Automate the Workflow with a CI/CD Tool&lt;/h3&gt;
&lt;p&gt;Integrate a CI/CD tool such as Jenkins, GitLab CI, CircleCI, or GitHub Actions to automate the Terraform workflow. The CI/CD tool will perform the following tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Terraform Init:&lt;/strong&gt; Initialize the Terraform environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform Plan:&lt;/strong&gt; Show what changes will be made to the infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform Apply:&lt;/strong&gt; Apply the changes and update the infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;FAQ:&lt;/strong&gt; &lt;em&gt;How do CI/CD tools manage state in Terraform?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Terraform uses a &lt;strong&gt;state file&lt;/strong&gt; to keep track of the current infrastructure. This state is crucial for Terraform to understand what exists in the real-world infrastructure versus what’s defined in code. Store the state file securely (e.g., using an S3 bucket or Terraform Cloud) so that CI/CD pipelines have access to the latest state during deployments.&lt;/p&gt;
&lt;h2&gt;Where Does Terraform Fit in DevOps?&lt;/h2&gt;
&lt;p&gt;Terraform is a critical tool in the &lt;strong&gt;DevOps toolkit&lt;/strong&gt; because it bridges the gap between infrastructure and development pipelines. It allows developers to treat infrastructure as code, enabling them to provision and manage infrastructure through automated, repeatable processes.&lt;/p&gt;
&lt;h3&gt;Key Benefits in a DevOps Workflow:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Continuous Delivery:&lt;/strong&gt; Terraform works hand-in-hand with CI/CD pipelines, allowing for continuous delivery of infrastructure updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version Control:&lt;/strong&gt; Infrastructure changes are tracked in the same version control system as application code, which makes rolling back to previous versions straightforward.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security and Compliance:&lt;/strong&gt; Terraform allows you to enforce security policies through automation, ensuring your infrastructure meets compliance requirements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;FAQ:&lt;/strong&gt; &lt;em&gt;How does Terraform enhance collaboration in DevOps?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;By integrating with CI/CD pipelines, Terraform enables teams to collaborate more effectively. Developers, operations, and security teams can review changes, apply policies, and ensure that infrastructure updates are safe and aligned with business needs all without manual intervention.&lt;/p&gt;
&lt;h2&gt;How to Create a CI/CD Pipeline in GitHub Actions for Terraform?&lt;/h2&gt;
&lt;p&gt;One of the easiest ways to deploy Terraform using CI/CD is by leveraging &lt;strong&gt;GitHub Actions&lt;/strong&gt;. GitHub Actions is a flexible CI/CD tool that allows you to automate workflows directly in your GitHub repository.&lt;/p&gt;
&lt;p&gt;Here’s a step-by-step guide to creating a CI/CD pipeline in GitHub Actions for Terraform:&lt;/p&gt;
&lt;h3&gt;Step 1: Define a Workflow&lt;/h3&gt;
&lt;p&gt;In your GitHub repository, create a &lt;code&gt;.github/workflows/main.yml&lt;/code&gt; file. This file defines the CI/CD pipeline.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Terraform Deployment

on:
  push:
    branches:
      - main

jobs:
  terraform:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Code
        uses: actions/checkout@v2

      - name: Set up Terraform
        uses: hashicorp/setup-terraform@v1
        with:
          terraform_version: 1.0.0

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        run: terraform plan

      - name: Terraform Apply
        run: terraform apply -auto-approve
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Add Security and Secrets&lt;/h3&gt;
&lt;p&gt;In GitHub Actions, you&amp;#39;ll need to store sensitive data (like cloud provider credentials) securely using &lt;strong&gt;GitHub Secrets&lt;/strong&gt;. This ensures that your pipeline can authenticate with the cloud provider without exposing credentials in the code.&lt;/p&gt;
&lt;h3&gt;Step 3: Trigger the Pipeline&lt;/h3&gt;
&lt;p&gt;The pipeline is triggered whenever changes are pushed to the &lt;code&gt;main&lt;/code&gt; branch, automating the entire Terraform workflow from initialization to applying changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FAQ:&lt;/strong&gt; &lt;em&gt;Why use GitHub Actions for Terraform?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;GitHub Actions is highly customizable and integrates natively with GitHub repositories, making it ideal for teams already using GitHub for source control. Its flexibility allows you to build, test, and deploy infrastructure with Terraform in a streamlined, automated way.&lt;/p&gt;
&lt;h2&gt;Best Practices for Terraform in CI/CD Pipelines&lt;/h2&gt;
&lt;p&gt;To get the most out of using Terraform in CI/CD pipelines, here are a few best practices to follow:&lt;/p&gt;
&lt;h3&gt;1. Use Remote State Storage&lt;/h3&gt;
&lt;p&gt;Store your Terraform state file in a remote backend (like an S3 bucket, Azure Blob, or Terraform Cloud) to ensure that CI/CD pipelines can always access the latest state. Remote state storage also prevents issues from multiple users or pipelines modifying the infrastructure simultaneously.&lt;/p&gt;
&lt;h3&gt;2. Perform Security and Compliance Checks&lt;/h3&gt;
&lt;p&gt;Use tools like &lt;strong&gt;Checkov&lt;/strong&gt; or &lt;strong&gt;TFLint&lt;/strong&gt; to scan your Terraform code for security vulnerabilities and best practices before applying it in production.&lt;/p&gt;
&lt;h3&gt;3. Test Infrastructure Changes in Staging&lt;/h3&gt;
&lt;p&gt;Before applying any changes to production, deploy the infrastructure in a staging environment. This ensures that any issues are caught early in the development lifecycle.&lt;/p&gt;
&lt;h3&gt;4. Automate Rollbacks&lt;/h3&gt;
&lt;p&gt;Always include a rollback strategy in your CI/CD pipeline. In the event of a failed deployment, your pipeline should automatically revert the infrastructure to the previous stable state.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Incorporating Terraform into your CI/CD pipeline is a no-brainer for teams looking to automate infrastructure deployments at scale. Whether you’re using GitHub Actions, Jenkins, or any other CI/CD platform, Terraform’s flexibility and cross-cloud compatibility make it a powerful tool in your DevOps arsenal. By following best practices and ensuring security and compliance checks are part of your process, you can confidently deploy infrastructure changes faster and more reliably.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Terraform Documentation - HashiCorp.), &lt;a href=&quot;https://www.terraform.io/docs&quot;&gt;https://www.terraform.io/docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub Actions Documentation.), &lt;a href=&quot;https://docs.github.com/en/actions&quot;&gt;https://docs.github.com/en/actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform Best Practices - HashiCorp Learn.), &lt;a href=&quot;https://learn.hashicorp.com/collections/terraform/best-practices&quot;&gt;https://learn.hashicorp.com/collections/terraform/best-practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using Terraform with CI/CD - HashiCorp Learn.), &lt;a href=&quot;https://learn.hashicorp.com/tutorials/terraform/cicd-pipeline&quot;&gt;https://learn.hashicorp.com/tutorials/terraform/cicd-pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Infrastructure as Code - AWS Whitepapers.), &lt;a href=&quot;https://aws.amazon.com/whitepapers/?whitepapers-main.sort-by=item.additionalFields.sortDate&amp;whitepapers-main.sort-order=desc&amp;awsf.whitepapers-content-type=*all&amp;awsf.whitepapers-global-methodology=*all&amp;awsf.whitepapers-tech-category=tech-categories%23devops&quot;&gt;https://aws.amazon.com/whitepapers/?whitepapers-main.sort-by=item.additionalFields.sortDate&amp;amp;whitepapers-main.sort-order=desc&amp;amp;awsf.whitepapers-content-type=*all&amp;amp;awsf.whitepapers-global-methodology=*all&amp;amp;awsf.whitepapers-tech-category=tech-categories%23devops&lt;/a&gt; (Search for &amp;quot;Infrastructure as Code&amp;quot;)&lt;/li&gt;
&lt;li&gt;Terraform State Management - HashiCorp.), &lt;a href=&quot;https://www.terraform.io/docs/language/state/index.html&quot;&gt;https://www.terraform.io/docs/language/state/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Checkov - Bridgecrew by Prisma Cloud.), &lt;a href=&quot;https://www.checkov.io/&quot;&gt;https://www.checkov.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;TFLint - Terraform Linter.), &lt;a href=&quot;https://github.com/terraform-linters/tflint&quot;&gt;https://github.com/terraform-linters/tflint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Continuous Delivery with Terraform and GitHub Actions&amp;quot; - (Example: Blog post from a reputable tech blog like Medium, DEV.to, or a company blog.), [Link to a relevant blog post]&lt;/li&gt;
&lt;li&gt;&amp;quot;Automating Terraform Deployments with GitLab CI&amp;quot; - (Example: GitLab documentation or a community tutorial.), [Link to a relevant resource]&lt;/li&gt;
&lt;li&gt;&amp;quot;Best Practices for Managing Terraform in a Team&amp;quot; - (Example: Article from Gruntwork or similar IaC focused company.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Securing Your IaC Pipeline&amp;quot; - (Example: Article from a cloud security vendor or a security-focused blog.), [Link to a relevant resource]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>DevOps</category><category>Infrastructure as Code</category><category>CI/CD</category><category>Terraform</category><category>Cloud Automation</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0067-deploying-infrastructure-with-terraform-in-ci-cd-pipelines/hero.jpg" length="0" type="image/jpeg"/></item><item><title>When to Use Serverless?</title><link>https://mkabumattar.com/blog/post/when-to-use-serverless/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/when-to-use-serverless/</guid><description>Discover when to use serverless architecture in your projects. Learn about its advantages, real-world success stories, and scenarios where serverless is the best fit. Explore the pros and cons to make informed decisions.</description><pubDate>Sun, 26 May 2024 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As a DevOps engineer working with AWS, understanding when to use serverless architecture can be a game-changer for your projects. Serverless computing offers numerous benefits, but it&amp;#39;s essential to know when it is the right choice. In this comprehensive guide, we&amp;#39;ll delve into the ideal scenarios for using serverless, explore its advantages and disadvantages, and provide real-world success stories to illustrate its effectiveness.&lt;/p&gt;
&lt;h3&gt;Understanding Serverless Architecture&lt;/h3&gt;
&lt;p&gt;With &lt;strong&gt;Serverless architecture&lt;/strong&gt;, developers can create and operate apps without having to worry about maintaining server infrastructure. All you have to do is write code AWS takes care of server deployment, scaling, and maintenance. An excellent illustration of a serverless service that runs code in response to events while autonomously controlling the necessary computational resources is AWS Lambda. Applications can be easily deployed and scaled thanks to the abstraction layer&amp;#39;s simplification of development and operations.&lt;/p&gt;
&lt;h3&gt;When to Consider Going Serverless?&lt;/h3&gt;
&lt;h4&gt;Support Microservices Architecture&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Microservices architecture&lt;/strong&gt; is a perfect match for serverless computing. Microservices are single-purpose, tiny, independently deployable services. Every microservice can be handled by serverless functions, such as AWS Lambda, which enables autonomous scaling, deployment, and management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: An E-commerce Platform&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An e-commerce platform can benefit from serverless by breaking down functionalities into microservices. For instance, separate Lambda functions can handle user authentication, order processing, and payment handling. This decoupling enhances scalability and resilience, ensuring that each microservice can scale independently based on demand.&lt;/p&gt;
&lt;h4&gt;Event-Driven Applications&lt;/h4&gt;
&lt;p&gt;When functions are triggered by events, such file uploads, HTTP requests, or database changes, serverless programming shines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: Image Processing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Think about a program that handles picture uploads to an S3 bucket. AWS Lambda can be used to activate a function that will process every image that is uploaded, increasing system responsiveness and efficiency. By utilizing serverless architecture&amp;#39;s event-driven design, this configuration makes sure resources are only used when necessary.&lt;/p&gt;
&lt;h4&gt;Applications with Variable Workloads&lt;/h4&gt;
&lt;p&gt;Serverless architecture offers significant advantages for applications with fluctuating workloads. Conventional servers could find it difficult to handle varying traffic, which could result in either over- or under-provisioning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: Social Media Analytics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Serverless computing enables applications such as social media analytics that see spikes in traffic during particular events or periods to autonomously scale in response to incoming requests, guaranteeing peak performance without requiring human involvement. Because of its adaptability, serverless architecture is perfect for managing erratic traffic patterns.&lt;/p&gt;
&lt;h3&gt;How Does Serverless Accelerate Development and Deployment?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Quicken Development and Implementation:&lt;/strong&gt; The time and effort required to design, test, and deploy applications are decreased by the built-in integrations and abstractions offered by serverless platforms. The entire development process is accelerated by features like automated scaling, integrated monitoring, and streamlined deployment pipelines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: Rapid Prototyping&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Prototyping fast is crucial in a startup environment. Developers may evaluate and deploy new features quicker with serverless, as it removes issues with the underlying infrastructure and speeds up time to market. Startups are able to innovate more quickly and adjust to market changes more effectively because to its rapid iteration feature.&lt;/p&gt;
&lt;h3&gt;Is Serverless Cost Efficient for Sporadic Usage?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Cost Efficiency in Sporadic Usage:&lt;/strong&gt; Serverless architecture is particularly cost-effective for applications with intermittent usage patterns. Since you pay only for the compute time used, it can lead to significant cost savings compared to running dedicated servers continuously.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: Cron Jobs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Think about a cron task that processes data several times each day. AWS Lambda is considerably more cost-effective than running a server all the time because you simply pay for the execution time. For crucial but rare operations, this pay-per-use strategy works well.&lt;/p&gt;
&lt;h3&gt;Real-World Success Stories for Serverless Architecture&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s look at some &lt;strong&gt;real-world success stories&lt;/strong&gt; that highlight the benefits of serverless architecture:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Netflix:&lt;/strong&gt; To manage traffic spikes during popular shows and events, the streaming behemoth employs serverless architecture. Netflix can automatically scale to meet demand by utilizing AWS Lambda, which guarantees a smooth viewing experience for users.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;iRobot:&lt;/strong&gt; The business that created the well-known Roomba vacuum cleaner processes data from its army of robots using AWS Lambda. With this method, iRobot can scale dynamically in response to data volume, resulting in processing that is both economical and effective.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Financial Times:&lt;/strong&gt; This renowned publication uses serverless architecture to manage content delivery. AWS Lambda helps the Financial Times ensure their content is delivered reliably and quickly to a global audience.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;When Serverless Might Not Be the Best Fit?&lt;/h3&gt;
&lt;h4&gt;Long-Running Processes&lt;/h4&gt;
&lt;p&gt;Serverless architecture is not suitable for &lt;strong&gt;long-running processes&lt;/strong&gt;. For instance, the maximum execution duration for AWS Lambda is fifteen minutes. Conventional server-based solutions may be more suitable for activities requiring longer processing periods. For long-running tasks, think about utilizing ECS or dedicated EC2 instances.&lt;/p&gt;
&lt;h4&gt;Fine-Grained Control&lt;/h4&gt;
&lt;p&gt;The abstraction of underlying infrastructure in serverless computing may be a disadvantage for users who require precise control over the environment. Applications that demand particular networking settings or hardware configurations might not be a good fit for serverless architecture. Containers or traditional virtual machines might provide the required control.&lt;/p&gt;
&lt;h4&gt;Debugging and Monitoring&lt;/h4&gt;
&lt;p&gt;Although serverless makes deployment simpler, &lt;strong&gt;monitoring and debugging&lt;/strong&gt; may become more difficult. Debugging and tracing problems with serverless functions might be difficult due to their transient nature. Though they can be useful, tools like X-Ray and AWS CloudWatch still have more complexity than in traditional setups. Make sure you have effective monitoring and logging procedures in place.&lt;/p&gt;
&lt;h4&gt;Vendor Lock-In&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Vendor Lock-In&lt;/strong&gt; When using serverless architecture, &lt;strong&gt;vendor lock-in&lt;/strong&gt; must be taken into account. It may be challenging to switch providers if you are highly dependent on one&amp;#39;s services. It&amp;#39;s critical to balance the advantages of working with a single provider with any potential concerns. Considering mobility while designing can help to reduce some of these concerns.&lt;/p&gt;
&lt;h4&gt;State Management&lt;/h4&gt;
&lt;p&gt;Serverless functions are stateless by nature, making &lt;strong&gt;state management&lt;/strong&gt; more complex. Applications requiring persistent state across function executions may need to use additional services like AWS DynamoDB or S3, adding complexity to the architecture. Design patterns such as event sourcing or using stateful services can address this challenge.&lt;/p&gt;
&lt;h4&gt;Limited Offline Functionality&lt;/h4&gt;
&lt;p&gt;There is &lt;strong&gt;limited offline functionality&lt;/strong&gt; with serverless functions since they usually need an internet connection to communicate with cloud services. A serverless method might not be the best choice for applications that must run offline or in disconnected situations. Take into consideration hybrid architectures that blend offline-capable and serverless components.&lt;/p&gt;
&lt;h3&gt;Pros and Cons of Serverless Architecture&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s summarize the &lt;strong&gt;pros and cons&lt;/strong&gt; of serverless architecture:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cost Efficiency:&lt;/strong&gt; Pay only for what you use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; Automatic scaling based on demand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced Operational Overhead:&lt;/strong&gt; No need to manage servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster Development:&lt;/strong&gt; Focus on writing code rather than managing infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Execution Time Limits:&lt;/strong&gt; Not suitable for long-running processes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cold Start Latency:&lt;/strong&gt; Initial request can be slower due to function spin-up time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex State Management:&lt;/strong&gt; Stateless nature can complicate state management.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limited Offline Functionality:&lt;/strong&gt; Requires internet connectivity for cloud interactions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Many benefits can be gained from serverless architecture, especially for systems with fluctuating workloads, microservices, and event-driven functionality. It increases cost effectiveness, speeds up development, and scales itself. When determining whether serverless is the best option for your project, it&amp;#39;s crucial to take into account its restrictions, including possible latency problems and execution time limits.&lt;/p&gt;
&lt;p&gt;You may make selections that best fit the requirements and commercial objectives of your application by knowing when to employ serverless and when to choose traditional architectures. More flexible, scalable, and affordable solutions can result from properly utilizing serverless.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;AWS Lambda Documentation.), &lt;a href=&quot;https://aws.amazon.com/lambda/features/&quot;&gt;https://aws.amazon.com/lambda/features/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Serverless Computing? - AWS.), &lt;a href=&quot;https://aws.amazon.com/serverless/&quot;&gt;https://aws.amazon.com/serverless/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Serverless Architectures - Martin Fowler.), &lt;a href=&quot;https://martinfowler.com/articles/serverless.html&quot;&gt;https://martinfowler.com/articles/serverless.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;When (and When Not) to Use Serverless - Serverless Framework Blog.), &lt;a href=&quot;https://www.serverless.com/blog/when-to-use-serverless&quot;&gt;https://www.serverless.com/blog/when-to-use-serverless&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Lambda Best Practices - AWS Documentation.), &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microservices with Serverless - AWS Whitepapers.), &lt;a href=&quot;https://aws.amazon.com/whitepapers/?whitepapers-main.sort-by=item.additionalFields.sortDate&amp;whitepapers-main.sort-order=desc&amp;awsf.whitepapers-content-type=*all&amp;awsf.whitepapers-global-methodology=*all&amp;awsf.whitepapers-tech-category=tech-categories%23serverless&quot;&gt;https://aws.amazon.com/whitepapers/?whitepapers-main.sort-by=item.additionalFields.sortDate&amp;amp;whitepapers-main.sort-order=desc&amp;amp;awsf.whitepapers-content-type=*all&amp;amp;awsf.whitepapers-global-methodology=*all&amp;amp;awsf.whitepapers-tech-category=tech-categories%23serverless&lt;/a&gt; (Search for &amp;quot;Microservices Serverless&amp;quot;)&lt;/li&gt;
&lt;li&gt;Event-Driven Architecture - AWS.), &lt;a href=&quot;https://aws.amazon.com/event-driven-architecture/&quot;&gt;https://aws.amazon.com/event-driven-architecture/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Serverless Cost Optimization - (Example: Article from a cloud cost management blog or AWS documentation.), [Link to a relevant resource on serverless cost optimization]&lt;/li&gt;
&lt;li&gt;Netflix Case Study on Serverless - (Example: AWS Case Studies or Netflix Tech Blog.), [Link to Netflix serverless case study]&lt;/li&gt;
&lt;li&gt;iRobot Case Study on AWS Lambda - (Example: AWS Case Studies.), [Link to iRobot serverless case study]&lt;/li&gt;
&lt;li&gt;Serverless Framework Documentation.), &lt;a href=&quot;https://www.serverless.com/framework/docs/&quot;&gt;https://www.serverless.com/framework/docs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;The Pros and Cons of Serverless Architecture&amp;quot; - (Example: Article from a reputable tech publication like InfoQ, The New Stack.), [Link to a relevant article discussing pros and cons]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Serverless</category><category>Cloud Computing</category><category>DevOps</category><category>AWS</category><category>Software Architecture</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0065-when-to-use-serverless/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Why You Should Not Use Else Statements in Your Code</title><link>https://mkabumattar.com/blog/post/why-you-should-not-use-else-statements/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/why-you-should-not-use-else-statements/</guid><description>Discover why avoiding else statements can lead to cleaner, more maintainable code. Learn about guard clauses, establishing contracts, and handling new conditions efficiently. Explore practical examples and best practices in software engineering.</description><pubDate>Fri, 24 May 2024 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In software engineering, how you structure your code can significantly impact its readability, maintainability, and overall quality. One often-debated topic is the use of else statements. While they seem straightforward, avoiding else statements can lead to cleaner and more understandable code. In this post, we’ll explore why you should reconsider using else statements and introduce some alternative approaches.&lt;/p&gt;
&lt;h3&gt;What Is a Guard Clause?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Guard clauses&lt;/strong&gt; are a powerful alternative to else statements. A guard clause is a condition at the beginning of a function that handles special cases or invalid input immediately, allowing the main logic to flow without nested conditions.&lt;/p&gt;
&lt;h4&gt;Example: Using Guard Clauses&lt;/h4&gt;
&lt;p&gt;Here’s a simple example in Python to illustrate the concept:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def process_order(order):
    if order.is_valid():
        if order.has_stock():
            if order.is_paid():
                return &amp;quot;Order processed&amp;quot;
            else:
                return &amp;quot;Order not paid&amp;quot;
        else:
            return &amp;quot;Out of stock&amp;quot;
    else:
        return &amp;quot;Invalid order&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how the nested conditions make the code harder to follow. Now, let’s refactor it using guard clauses:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def process_order(order):
    if not order.is_valid():
        return &amp;quot;Invalid order&amp;quot;

    if not order.has_stock():
        return &amp;quot;Out of stock&amp;quot;

    if not order.is_paid():
        return &amp;quot;Order not paid&amp;quot;

    return &amp;quot;Order processed&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By handling special cases early, the main logic is clearer and easier to read. Guard clauses reduce indentation and highlight the main flow of the function.&lt;/p&gt;
&lt;h3&gt;How Does It Establish a Contract?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Establishes a Contract:&lt;/strong&gt; Using guard clauses can establish a clear contract for your functions. This means defining what conditions must be met for the function to proceed with its main logic.&lt;/p&gt;
&lt;p&gt;When you handle edge cases at the beginning, it becomes immediately obvious what preconditions must be satisfied, making the function’s behavior more predictable and understandable.&lt;/p&gt;
&lt;h4&gt;Example: Establishing a Contract&lt;/h4&gt;
&lt;p&gt;Consider a function that processes user input:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def process_input(user_input):
    if user_input is None:
        raise ValueError(&amp;quot;Input cannot be None&amp;quot;)

    if not isinstance(user_input, str):
        raise TypeError(&amp;quot;Input must be a string&amp;quot;)

    if user_input == &amp;quot;&amp;quot;:
        raise ValueError(&amp;quot;Input cannot be empty&amp;quot;)

    # Main processing logic
    return user_input.strip().upper()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By establishing a contract with guard clauses, you ensure that the function’s main logic operates under clearly defined conditions. This approach not only makes the code more readable but also more reliable.&lt;/p&gt;
&lt;h3&gt;What About Adding New Conditions?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Adding New Conditions:&lt;/strong&gt; One of the challenges with else statements is that they can lead to deeply nested code, especially when adding new conditions. Guard clauses simplify this by allowing new conditions to be added without increasing indentation levels.&lt;/p&gt;
&lt;h4&gt;Example: Adding New Conditions with Guard Clauses&lt;/h4&gt;
&lt;p&gt;Suppose you need to extend the previous order processing function to check for a new condition, such as checking if the order is from a preferred customer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def process_order(order):
    if not order.is_valid():
        return &amp;quot;Invalid order&amp;quot;

    if not order.has_stock():
        return &amp;quot;Out of stock&amp;quot;

    if not order.is_paid():
        return &amp;quot;Order not paid&amp;quot;

    if not order.is_preferred_customer():
        return &amp;quot;Standard order processing&amp;quot;

    return &amp;quot;Priority order processing&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adding new conditions is straightforward and does not complicate the main logic flow. Each condition is handled explicitly and independently.&lt;/p&gt;
&lt;h3&gt;When Can You Use Else?&lt;/h3&gt;
&lt;p&gt;Despite the advantages of avoiding else statements, there are situations where using else can be appropriate, especially when it improves readability or when dealing with mutually exclusive conditions that naturally fall into an if-else pattern.&lt;/p&gt;
&lt;h4&gt;Example: Appropriate Use of Else&lt;/h4&gt;
&lt;p&gt;For instance, in a simple function that classifies numbers, using else can make the code more concise and clear:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def classify_number(number):
    if number &amp;gt; 0:
        return &amp;quot;Positive&amp;quot;
    elif number &amp;lt; 0:
        return &amp;quot;Negative&amp;quot;
    else:
        return &amp;quot;Zero&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, the else statement helps to clearly express the mutually exclusive nature of the conditions. The function is simple enough that the else statement doesn’t hinder readability.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Avoiding else statements can lead to cleaner, more maintainable code by leveraging guard clauses and establishing clear contracts for your functions. By handling edge cases upfront and keeping the main logic straightforward, your code becomes easier to read and understand. However, remember that else statements are not inherently bad and can be useful in certain contexts, especially for mutually exclusive conditions.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Fowler, Martin. &amp;quot;Replace Nested Conditional with Guard Clauses.&amp;quot; Refactoring.com.), &lt;a href=&quot;https://refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html&quot;&gt;https://refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Martin, Robert C. &amp;quot;Clean Code: A Handbook of Agile Software Craftsmanship.&amp;quot; Prentice Hall, 2008. (Chapter on Functions, specifically regarding conditional complexity.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Guard Clauses: A Simple Way to Write Cleaner Code&amp;quot; - (Example: Article from a tech blog like freeCodeCamp, Medium, or DEV.to.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;The Problem with Else&amp;quot; - (Example: Blog post discussing the downsides of else statements.), [Link to a relevant blog post]&lt;/li&gt;
&lt;li&gt;&amp;quot;Python Anti-Patterns: The Else Clause&amp;quot; - (Example: Python-specific article on coding practices.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Refactoring Guru: Guard Clause.&amp;quot;), &lt;a href=&quot;https://refactoring.guru/replace-nested-conditional-with-guard-clauses&quot;&gt;https://refactoring.guru/replace-nested-conditional-with-guard-clauses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Code Smells: Nested Conditionals&amp;quot; - (Example: Article discussing code smells and how to fix them.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Writing Readable Code: Tips and Best Practices&amp;quot; - (Example: General guide on code readability.), [Link to a relevant guide]&lt;/li&gt;
&lt;li&gt;&amp;quot;Software Design Principles: Single Responsibility Principle&amp;quot; - (Relates to functions doing one thing well, often aided by guard clauses.), [Link to an article on SRP]&lt;/li&gt;
&lt;li&gt;&amp;quot;When is it OK to use an Else statement?&amp;quot; - (Example: Discussion forum or Q&amp;amp;A site like Stack Overflow.), [Link to a relevant discussion]&lt;/li&gt;
&lt;li&gt;&amp;quot;Effective Java&amp;quot; by Joshua Bloch. (While Java-specific, principles on clear method design are broadly applicable.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;The Art of Readable Code&amp;quot; by Dustin Boswell and Trevor Foucher.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Software Engineering</category><category>Programming Best Practices</category><category>Code Quality</category><category>Refactoring</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0064-why-you-should-not-use-else-statements/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Avoid Over-Engineering Your Code?</title><link>https://mkabumattar.com/blog/post/how-to-avoid-over-engineering-your-code/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-avoid-over-engineering-your-code/</guid><description>Learn how to avoid over-engineering your code in software development. Discover the causes, symptoms, and practical strategies to maintain simplicity and align with business needs. Stay focused on creating efficient, maintainable software.</description><pubDate>Wed, 22 May 2024 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In software development, over-engineering is a typical mistake that can result in more complexity, longer development periods, and superfluous functionality. This blog article discusses how to avoid over-engineering your code and provides insightful guidance to help you stay committed to writing effective, maintainable software.&lt;/p&gt;
&lt;h3&gt;What’s the Problem with Over-Engineering?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Over-engineering&lt;/strong&gt; occurs when developers add unnecessary complexity to the program. This could manifest as too complicated solutions, superfluous features, or overly abstract ideas that don&amp;#39;t genuinely aid in solving the current issue.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Enhanced Complexity:&lt;/strong&gt; Understanding, maintaining, and debugging excessively complicated code becomes more challenging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prolonged Development Times:&lt;/strong&gt; Adding unnecessary features takes time and resources away from more crucial tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Confusion:&lt;/strong&gt; Complicated software may be difficult for users to navigate and confusing for them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Preventing these issues requires understanding their root causes as well as effective treatment methods.&lt;/p&gt;
&lt;h3&gt;What Role Do Context and Human Factors Play?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Context and Human Factor&lt;/strong&gt; significantly influence the tendency to over-engineer. Developers often have the best intentions but can be swayed by various factors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Perfectionism:&lt;/strong&gt; A desire to create flawless, future-proof solutions can lead to adding unnecessary complexity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fear of Change:&lt;/strong&gt; Developers might over-engineer in an attempt to anticipate and accommodate every possible future requirement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Peer Pressure:&lt;/strong&gt; In collaborative environments, there can be an implicit pressure to demonstrate advanced skills through complex solutions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Understanding these human factors can help developers become more mindful of their decision-making processes.&lt;/p&gt;
&lt;h3&gt;What Are the Symptoms of Excessive Engineering?&lt;/h3&gt;
&lt;p&gt;Recognizing the &lt;strong&gt;Symptoms of Excessive Engineering&lt;/strong&gt; is the first step toward addressing it. Here are some common signs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Overly Complicated Code:&lt;/strong&gt; Code that uses complex patterns or structures without clear benefits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redundant Features:&lt;/strong&gt; Implementing features that are rarely or never used.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Excessive Documentation:&lt;/strong&gt; Detailed documentation for minor components, indicating a focus on trivial details rather than essential functionality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High Maintenance Overhead:&lt;/strong&gt; Frequent and time-consuming maintenance tasks due to the code&amp;#39;s complexity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By identifying these symptoms early, you can take corrective action before the situation escalates.&lt;/p&gt;
&lt;h3&gt;What Causes Over-Engineering?&lt;/h3&gt;
&lt;p&gt;There are various reasons why &lt;strong&gt;over-engineering&lt;/strong&gt; occurs, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lack of Clearly Stated needs:&lt;/strong&gt; In an attempt to please everyone, developers may feel obliged to incorporate more functionality when demands are ambiguous or poorly expressed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;False Assumptions:&lt;/strong&gt; Believing that software is superior just because it is more complex or has more features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inadequate Communication:&lt;/strong&gt; When developers and stakeholders don&amp;#39;t communicate well, it might result in unbalanced priorities and unduly complex solutions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To address these causes, it is vital to foster a culture that prioritizes simplicity and clarity, improve communication, and establish clear standards.&lt;/p&gt;
&lt;h3&gt;How to Avoid Over-Engineering?&lt;/h3&gt;
&lt;p&gt;Several important tactics are involved in avoiding over-engineering:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Keep Your Eye on the Requirements:&lt;/strong&gt; Recognize and follow the most recent requirements. Don&amp;#39;t introduce features based on suppositions or potential future developments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accept Simplicity:&lt;/strong&gt; Look for the most straightforward way to satisfy the needs. Whenever possible, use simple, understandable code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Iterate and Enhance:&lt;/strong&gt; Use a methodical approach. Rather than striving to construct a perfect solution from the beginning, release a minimal viable product (MVP) and make improvements based on user input.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Encourage Communication:&lt;/strong&gt; To make sure that development initiatives are in line with company needs, keep the lines of communication open with all stakeholders.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review Code Frequently:&lt;/strong&gt; Review code frequently to find and remove superfluous complexity.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;How Does Over-Engineering Compare to Business Needs?&lt;/h3&gt;
&lt;p&gt;Understanding the relationship between &lt;strong&gt;Over-Engineering vs Business&lt;/strong&gt; is crucial. Business needs should always drive software development, not the other way around.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Value Delivery:&lt;/strong&gt; Focus on delivering value to users. Over-engineering often distracts from this goal by diverting resources to unnecessary features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost Efficiency:&lt;/strong&gt; Over-engineered solutions are typically more expensive to develop and maintain. Aligning development efforts with business priorities ensures better resource utilization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Satisfaction:&lt;/strong&gt; Simple, intuitive software enhances user satisfaction. Complex solutions can frustrate users and decrease engagement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By keeping business needs at the forefront, developers can create software that is both effective and efficient.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Software projects can be derailed by over-engineering, which increases complexity, raises costs, and lowers user satisfaction. Developers can produce software that is easier to maintain and use by comprehending the signs and symptoms of over-engineering and implementing preventative measures. Never forget to embrace simplicity, link development with business goals, iterate based on feedback, and concentrate on clear requirements.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Martin, Robert C. &amp;quot;Clean Code: A Handbook of Agile Software Craftsmanship.&amp;quot; Prentice Hall, 2008. (Chapters on Simplicity and Over-engineering.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;Fowler, Martin. &amp;quot;Is Design Dead?&amp;quot; MartinFowler.com, 2004. (Discusses evolutionary design and avoiding premature complexity.), &lt;a href=&quot;https://martinfowler.com/articles/designDead.html&quot;&gt;https://martinfowler.com/articles/designDead.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;KISS principle (Keep It Simple, Stupid).&amp;quot; Wikipedia.), &lt;a href=&quot;https://en.wikipedia.org/wiki/KISS_principle&quot;&gt;https://en.wikipedia.org/wiki/KISS_principle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;You Ain&amp;#39;t Gonna Need It (YAGNI).&amp;quot; Wikipedia.), &lt;a href=&quot;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&quot;&gt;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;The Perils of Over-Engineering&amp;quot; - (Example: Article from a software development blog like Coding Horror, Joel on Software, or a modern tech blog.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Symptoms of Over-Engineering Your Software&amp;quot; - (Example: Article from a tech publication or development community.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Agile Manifesto.&amp;quot; AgileManifesto.org. (Principles often guide against over-engineering.), &lt;a href=&quot;https://agilemanifesto.org/&quot;&gt;https://agilemanifesto.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;How to Balance Simplicity and Complexity in Software Design&amp;quot; - (Example: Discussion on Stack Exchange or a design-focused blog.), [Link to a relevant discussion or article]&lt;/li&gt;
&lt;li&gt;&amp;quot;The Lean Startup&amp;quot; by Eric Ries. (Focuses on MVP and iterative development, which helps avoid over-engineering.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Code Smells: Over-Engineering&amp;quot; - (Example: Article from Refactoring Guru or similar site.), [Link to a relevant article on code smells]&lt;/li&gt;
&lt;li&gt;&amp;quot;Pragmatic Programmer: From Journeyman to Master&amp;quot; by Andrew Hunt and David Thomas. (Offers practical advice on writing maintainable code.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Why Simplicity is the Key to Good Software Design&amp;quot; - (Example: Thought leadership piece from a respected developer or architect.), [Link to a relevant article]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Software Engineering</category><category>Programming Best Practices</category><category>Code Quality</category><category>Project Management</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0063-how-to-avoid-over-engineering-your-code/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Software Engineering Principles Every Developer Should Know</title><link>https://mkabumattar.com/blog/post/software-engineering-principles-every-developer-should-know/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/software-engineering-principles-every-developer-should-know/</guid><description>Explore essential software engineering principles every developer should know, including DRY, KISS, and YAGNI. Learn how these principles promote code reusability, simplicity, and focus on essential functionality. Plus, discover code examples in Python to illustrate these principles in action.</description><pubDate>Mon, 20 May 2024 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the dynamic world of software development, certain principles stand the test of time, guiding developers towards creating robust, maintainable, and efficient code. Let&amp;#39;s delve into these principles and understand why they are essential for every developer to know.&lt;/p&gt;
&lt;h2&gt;What Is the DRY Principle and Why Is It Important?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;DRY (Don&amp;#39;t Repeat Yourself)&lt;/strong&gt; is a fundamental principle that emphasizes the importance of code reusability.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Avoid Code Duplication:&lt;/strong&gt; Repeating the same code in multiple places increases the risk of errors and makes maintenance challenging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modularize Code:&lt;/strong&gt; Break down functionality into reusable modules or functions, reducing duplication and promoting consistency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s an example in Python that doesn&amp;#39;t adhere to the DRY principle, illustrating a common real-world scenario:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def create_user_profile(user_id, name, email):
    profile = {
        &amp;quot;id&amp;quot;: user_id,
        &amp;quot;name&amp;quot;: name,
        &amp;quot;email&amp;quot;: email,
        &amp;quot;welcome_message&amp;quot;: f&amp;quot;Welcome {name}! Your email is {email}.&amp;quot;
    }
    print(f&amp;quot;Creating profile for {name} with email {email}&amp;quot;)
    return profile

def send_welcome_email(name, email):
    message = f&amp;quot;Hello {name}, welcome to our platform! Please verify your email: {email}.&amp;quot;
    print(f&amp;quot;Sending email to {email}: {message}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code repeats the process of constructing welcome messages. Let&amp;#39;s refactor it to adhere to the DRY principle:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def format_welcome_message(name, email):
    return f&amp;quot;Hello {name}, welcome to our platform! Please verify your email: {email}.&amp;quot;

def create_user_profile(user_id, name, email):
    profile = {
        &amp;quot;id&amp;quot;: user_id,
        &amp;quot;name&amp;quot;: name,
        &amp;quot;email&amp;quot;: email,
        &amp;quot;welcome_message&amp;quot;: format_welcome_message(name, email)
    }
    print(f&amp;quot;Creating profile for {name} with email {email}&amp;quot;)
    return profile

def send_welcome_email(name, email):
    message = format_welcome_message(name, email)
    print(f&amp;quot;Sending email to {email}: {message}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By creating a single function to format welcome messages, we eliminate redundancy and improve maintainability.&lt;/p&gt;
&lt;h2&gt;How Does the KISS Principle Improve Software Development?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;KISS (Keep It Simple, Stupid)&lt;/strong&gt; advocates for simplicity in design and implementation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Clarity and Readability:&lt;/strong&gt; Simple code is easier to understand, debug, and maintain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduce Complexity:&lt;/strong&gt; Avoid over-engineering by choosing straightforward solutions over unnecessarily complex ones.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consider the following Python code snippet for logging user activities:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import logging

def log_user_activity(user_id, activity):
    logging.basicConfig(level=logging.DEBUG, format=&amp;#39;%(asctime)s %(message)s&amp;#39;)
    logger = logging.getLogger()
    log_message = f&amp;quot;User {user_id} performed {activity}.&amp;quot;
    if activity == &amp;#39;login&amp;#39;:
        logger.debug(log_message)
    elif activity == &amp;#39;logout&amp;#39;:
        logger.debug(log_message)
    elif activity == &amp;#39;error&amp;#39;:
        logger.error(log_message)
    else:
        logger.info(log_message)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code is more complex than necessary. Let&amp;#39;s simplify it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import logging

logging.basicConfig(level=logging.DEBUG, format=&amp;#39;%(asctime)s %(message)s&amp;#39;)
logger = logging.getLogger()

def log_user_activity(user_id, activity):
    log_message = f&amp;quot;User {user_id} performed {activity}.&amp;quot;
    logger.log(logging.DEBUG if activity in [&amp;#39;login&amp;#39;, &amp;#39;logout&amp;#39;] else logging.INFO, log_message)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using a more straightforward approach, we maintain functionality while enhancing readability and reducing complexity.&lt;/p&gt;
&lt;h2&gt;What Does YAGNI Mean in Software Development?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;YAGNI (You Aren&amp;#39;t Gonna Need It)&lt;/strong&gt; encourages developers to avoid adding functionality prematurely.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Focus on Requirements:&lt;/strong&gt; Implement only the features that are currently needed, avoiding speculative or unnecessary additions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid Over-Engineering:&lt;/strong&gt; By prioritizing essential functionality, developers can minimize complexity and reduce the risk of introducing bugs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consider the following Python code snippet for handling user permissions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def get_user_permissions(user_role, has_admin_rights, is_super_user, is_active):
    if not is_active:
        return &amp;quot;No permissions&amp;quot;
    if is_super_user:
        return &amp;quot;All permissions&amp;quot;
    if has_admin_rights:
        return &amp;quot;Admin permissions&amp;quot;
    if user_role == &amp;quot;editor&amp;quot;:
        return &amp;quot;Edit permissions&amp;quot;
    if user_role == &amp;quot;viewer&amp;quot;:
        return &amp;quot;View permissions&amp;quot;
    return &amp;quot;No permissions&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code over-engineers the permissions logic. Let&amp;#39;s simplify it by focusing on essential functionality:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def get_user_permissions(user_role):
    permissions = {
        &amp;quot;super_user&amp;quot;: &amp;quot;All permissions&amp;quot;,
        &amp;quot;admin&amp;quot;: &amp;quot;Admin permissions&amp;quot;,
        &amp;quot;editor&amp;quot;: &amp;quot;Edit permissions&amp;quot;,
        &amp;quot;viewer&amp;quot;: &amp;quot;View permissions&amp;quot;
    }
    return permissions.get(user_role, &amp;quot;No permissions&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By adhering to the YAGNI principle, we eliminate unnecessary complexity and focus on core requirements.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Code quality and maintainability can be greatly improved by comprehending and putting software engineering principles like DRY, KISS, and YAGNI into practice. These guidelines help programmers write effective, reliable, and maintainable software by encouraging code reuse, simplicity, and an emphasis on key features.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Hunt, Andrew, and David Thomas. &amp;quot;The Pragmatic Programmer: From Journeyman to Master.&amp;quot; Addison-Wesley Professional, 1999. (Introduced DRY.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;Martin, Robert C. &amp;quot;Clean Code: A Handbook of Agile Software Craftsmanship.&amp;quot; Prentice Hall, 2008. (Discusses KISS and other principles.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Don&amp;#39;t repeat yourself.&amp;quot; Wikipedia.), &lt;a href=&quot;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;KISS principle.&amp;quot; Wikipedia.), &lt;a href=&quot;https://en.wikipedia.org/wiki/KISS_principle&quot;&gt;https://en.wikipedia.org/wiki/KISS_principle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;You ain&amp;#39;t gonna need it (YAGNI).&amp;quot; Wikipedia.), &lt;a href=&quot;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&quot;&gt;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fowler, Martin. &amp;quot;Yagni.&amp;quot; MartinFowler.com.), &lt;a href=&quot;https://martinfowler.com/bliki/Yagni.html&quot;&gt;https://martinfowler.com/bliki/Yagni.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Software Design Principles: DRY, KISS, YAGNI&amp;quot; - (Example: Article from a tech blog like freeCodeCamp, Medium, or DEV.to.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;The Importance of Simplicity in Software Development&amp;quot; - (Example: Article discussing the KISS principle in depth.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Code Reuse: The Good, The Bad, and The Ugly&amp;quot; - (Example: Article discussing DRY and its implications.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;SOLID Principles for C# Developers&amp;quot; - Atree (While C#-focused, SOLID principles are related and often discussed alongside DRY, KISS, YAGNI.), &lt;a href=&quot;https://www.atree.com.au/insights/solid-principles-for-c-developers/&quot;&gt;https://www.atree.com.au/insights/solid-principles-for-c-developers/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Refactoring Guru: Code Smells.&amp;quot; (Discusses issues often solved by applying these principles.), &lt;a href=&quot;https://refactoring.guru/smells&quot;&gt;https://refactoring.guru/smells&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;97 Things Every Programmer Should Know: Collective Wisdom from the Experts&amp;quot; edited by Kevlin Henney. O&amp;#39;Reilly Media, 2010. (Contains essays touching on these principles.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Software Engineering</category><category>Programming Principles</category><category>Code Quality</category><category>Best Practices</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0062-software-engineering-principles-every-developer-should-know/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Phases of the Modernization Process</title><link>https://mkabumattar.com/blog/post/phases-of-the-modernization-process/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/phases-of-the-modernization-process/</guid><description>Discover the key phases of the modernization process. Learn how to align with business goals, understand dependencies, involve customers, and future-proof your IT infrastructure.</description><pubDate>Sat, 18 May 2024 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Modernizing IT infrastructure is essential for organizations to stay competitive, secure, and efficient. The modernization process, involves several strategic phases. Each phase is critical to ensure a smooth transition and to derive maximum value from modernization efforts. This blog post will walk you through these phases, answering key questions and providing insights to help you navigate this complex process.&lt;/p&gt;
&lt;h4&gt;Why Should You Determine The ‘Why’?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Determining The &amp;quot;Why&amp;quot;&lt;/strong&gt; is essential before starting any modernization process. Knowing why the modernization effort is being undertaken lays the groundwork for all other actions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Align with Business Objectives:&lt;/strong&gt; Make sure that the modernization is in line with your company&amp;#39;s goals. Having a clear &amp;quot;why&amp;quot; aids in determining the appropriate priorities, be they cost-cutting, performance-enhancing, or security-related.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Determine Pain Points:&lt;/strong&gt; Acknowledge the shortcomings and present difficulties with your current setup. This could involve scalability problems, security flaws, or antiquated technology.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can develop a modernization roadmap that directs your work and maintains the project&amp;#39;s relevance and focus by outlining the &amp;quot;why&amp;quot; in detail.&lt;/p&gt;
&lt;h4&gt;What Is the Importance of Discovery and Analysis?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Start with discovery and analysis&lt;/strong&gt; to get a thorough picture of your existing IT environment.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Evaluate Present Situation:&lt;/strong&gt; Make sure your current apps, processes, and infrastructure are all thoroughly inspected. This aids in determining what should be updated, swapped out, or kept.
-- &lt;strong&gt;Examine Dependencies:&lt;/strong&gt; It&amp;#39;s essential to comprehend how various parts work together and depend on one another. This aids in relocation planning without interfering with corporate operations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Findings and analysis paint a clear picture of the current configuration, emphasizing problem areas and promoting well-informed decision-making.&lt;/p&gt;
&lt;h4&gt;Why Is Modernization Not Just a Project, But A Process?&lt;/h4&gt;
&lt;p&gt;Modernization is a continuous process. &lt;strong&gt;Recognize that this is a process rather than a project&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Constant Improvement:&lt;/strong&gt; The state of technology is ever-changing. Modernization is to be viewed as an ongoing endeavor to stay abreast with industry best practices and technological breakthroughs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agile Methodology:&lt;/strong&gt; Take on an agile mentality. Divide the modernization process into smaller, more doable activities, then iterate in response to feedback and performance indicators.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A long-term approach that prioritizes adaptability above one-time projects guarantees modernization&amp;#39;s success.&lt;/p&gt;
&lt;h4&gt;How to Evaluate Both Current and Future Value?&lt;/h4&gt;
&lt;p&gt;When modernizing, it’s essential to &lt;strong&gt;Consider Both Current And Future Value&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Short-term Gains:&lt;/strong&gt; Identify immediate benefits such as improved performance, cost savings, and enhanced security.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Long-term Benefits:&lt;/strong&gt; Look beyond the immediate gains. Consider how the modernization will support future business needs, scalability, and adaptability to new technologies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Balancing current and future value helps in making decisions that are beneficial in the long run.&lt;/p&gt;
&lt;h4&gt;How to Discover, Classify, and Map the Flow of Data?&lt;/h4&gt;
&lt;p&gt;Data is at the heart of modernization. &lt;strong&gt;Discover, Classify And Map The Flow Of Data&lt;/strong&gt; to ensure seamless integration and security.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data Discovery:&lt;/strong&gt; Identify all data sources and how data flows through your system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Classification:&lt;/strong&gt; Classify data based on sensitivity, criticality, and compliance requirements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mapping:&lt;/strong&gt; Create a detailed map of data flow to understand how data moves and where it resides.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This step ensures that data is properly managed, secure, and compliant with regulations.&lt;/p&gt;
&lt;h4&gt;How to Inventory Existing Apps and Their Interdependencies?&lt;/h4&gt;
&lt;p&gt;A thorough inventory of your applications and their interdependencies is crucial. &lt;strong&gt;Inventory Existing Apps And Their Interdependencies&lt;/strong&gt; to avoid disruptions during the transition.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Catalog Applications:&lt;/strong&gt; List all applications in use, including legacy systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Understand Dependencies:&lt;/strong&gt; Document how these applications interact with each other and with the infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This inventory helps in planning the migration strategy and minimizing risks.&lt;/p&gt;
&lt;h4&gt;Why Is Getting Input from Your Customers Important?&lt;/h4&gt;
&lt;p&gt;The user experience should be a key component of modernization. To match your efforts with the needs of your customers, get their input.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Customer feedback:&lt;/strong&gt; Gather end users&amp;#39; opinions to learn about their expectations and trouble areas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User-Centric Design:&lt;/strong&gt; To increase user satisfaction and adoption, modernize your strategy by incorporating customer insights.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Customers&amp;#39; involvement&lt;/strong&gt; guarantees that modernization initiatives are user-centric and address practical needs.&lt;/p&gt;
&lt;h4&gt;How to Approach Migration, Re-architecture, or Re-platform?&lt;/h4&gt;
&lt;p&gt;Deciding between migration, re-architecture, or re-platforming is a key decision. Consider creating a &lt;strong&gt;migration or re-architecture or re-platform diagram&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Migration:&lt;/strong&gt; Move applications and data to new environments with minimal changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Re-architecture:&lt;/strong&gt; Redesign applications to take full advantage of modern technologies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Re-platform:&lt;/strong&gt; Shift applications to new platforms with some optimizations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Choosing the right approach depends on your goals, existing infrastructure, and future needs.&lt;/p&gt;
&lt;h4&gt;How to Think About Future-Proofing Your Modernization Efforts?&lt;/h4&gt;
&lt;p&gt;To make sure that your modernization initiatives endure over time, &lt;strong&gt;consider future-proofing&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; Create systems that grow with your company.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexibility:&lt;/strong&gt; Make sure that new technologies and business models can be included into your infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security:&lt;/strong&gt; To guard against changing dangers, implement strong security measures.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Creating an IT infrastructure that is flexible and robust is part of future-proofing.&lt;/p&gt;
&lt;h4&gt;Why Adopt a Microservices Approach?&lt;/h4&gt;
&lt;p&gt;Implementing a &lt;strong&gt;Microservices Approach&lt;/strong&gt; will greatly improve your modernization endeavors.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Modularity:&lt;/strong&gt; Divide larger programs into more manageable, standalone services that may be independently designed, implemented, and expanded.
-- &lt;strong&gt;Resilience:&lt;/strong&gt; The microservices design facilitates easier application management and updates while enhancing fault tolerance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This method simplifies the management of big, monolithic programs while enhancing agility.&lt;/p&gt;
&lt;h4&gt;How to Develop a Detailed Onboarding Program?&lt;/h4&gt;
&lt;p&gt;To ensure smooth adoption, &lt;strong&gt;Develop A Detailed Onboarding Program&lt;/strong&gt; for your team and stakeholders.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Training:&lt;/strong&gt; Provide comprehensive training to ensure that everyone understands the new systems and processes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation:&lt;/strong&gt; Create detailed documentation to support ongoing learning and troubleshooting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support:&lt;/strong&gt; Establish a support system to assist users during the transition.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A well-planned onboarding program ensures that your team is prepared and confident in using the new infrastructure.&lt;/p&gt;
&lt;h3&gt;What Is the Strategy for Modernizing Applications in the AWS Cloud?&lt;/h3&gt;
&lt;p&gt;Modernizing applications by leveraging the AWS Cloud offers significant benefits, including enhanced scalability, security, and cost-efficiency. A well-defined strategy is essential to maximize these advantages and ensure a smooth transition. Here’s a step-by-step approach to modernizing applications in the AWS Cloud:&lt;/p&gt;
&lt;h4&gt;How to Start with a Comprehensive Assessment?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analyze the System of Infrastructure as It Is Now:&lt;/strong&gt; Start by conducting a thorough evaluation of your current on-premises infrastructure. Determine which apps, taking into account their cost, performance, and strategic significance, are the best candidates for migration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Assess Application Eligibility for Cloud Migration:&lt;/strong&gt; Not every application is appropriate for the cloud. To determine whether migrating a particular application is feasible and beneficial, use AWS tools such as the AWS Migration Evaluator.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Why Is a Well-Defined Migration Plan Crucial?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Create a thorough migration strategy&lt;/strong&gt; that details the procedures and deadlines for transferring applications to the AWS Cloud.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Select the Best Migration Approach:&lt;/strong&gt; Make the decision to re-host, re-platform, or re-architect apps. Every strategy has advantages and complications of its own. As an illustration:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rehost:&lt;/strong&gt; Often referred to as &amp;quot;lift and shift,&amp;quot; this tactic is transferring programs to AWS with little to no modification.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replatform:&lt;/strong&gt; Without altering the fundamental architecture, make a few cloud optimizations to reap noticeable gains.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Re-architect:&lt;/strong&gt; Rework programs to make the most of AWS services and enhance manageability, scalability, and performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;How to Leverage AWS Services for Modernization?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Utilize AWS Services&lt;/strong&gt; to streamline the modernization process and enhance application functionality.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Compute Services:&lt;/strong&gt; Use AWS EC2 for scalable compute capacity, or opt for AWS Lambda for a serverless architecture that automatically scales with demand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage Solutions:&lt;/strong&gt; Take advantage of AWS S3 for scalable object storage and AWS RDS for managed relational databases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Networking:&lt;/strong&gt; Implement AWS VPC to create isolated cloud resources, ensuring secure and controlled access to your applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;How to Ensure Security and Compliance?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Adopt AWS Security Best Practices&lt;/strong&gt; to protect your applications and data during and after the migration.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Identity and Access Management:&lt;/strong&gt; Use AWS IAM to manage user permissions and secure access to your AWS resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Encryption:&lt;/strong&gt; Implement encryption for data at rest and in transit using AWS KMS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compliance:&lt;/strong&gt; Leverage AWS compliance certifications and tools to meet industry standards and regulatory requirements.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Why Is Automation Important in AWS?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Automate Deployment and Management&lt;/strong&gt; to improve efficiency and reduce errors.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Infrastructure as Code (IaC):&lt;/strong&gt; Use AWS CloudFormation or Terraform to automate the provisioning of your AWS infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI/CD Pipelines:&lt;/strong&gt; Implement continuous integration and continuous deployment (CI/CD) pipelines using AWS CodePipeline, AWS CodeBuild, and AWS CodeDeploy to automate the build, test, and deployment processes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;How to Monitor and Optimize Post-Migration?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Continuous Monitoring and Optimization&lt;/strong&gt; are key to maintaining performance and cost-efficiency.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Monitoring Tools:&lt;/strong&gt; Utilize AWS CloudWatch to monitor application performance and AWS CloudTrail for logging and tracking API calls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost Management:&lt;/strong&gt; Use AWS Cost Explorer and AWS Trusted Advisor to monitor and optimize your cloud spending.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;How to Plan for Continuous Improvement?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Continuous Improvement and Innovation&lt;/strong&gt; should be integral to your modernization strategy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Regular Reviews:&lt;/strong&gt; Conduct regular reviews and updates of your AWS infrastructure to incorporate new services and best practices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stay Updated:&lt;/strong&gt; Keep abreast of the latest AWS innovations and updates to leverage new features and capabilities that can further enhance your applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Modernizing applications in the AWS Cloud requires a strategic approach, starting with a thorough assessment, followed by a well-defined migration plan, leveraging AWS services, ensuring security, and embracing automation. Post-migration, continuous monitoring and optimization, along with a focus on continuous improvement, will help your organization fully realize the benefits of cloud modernization.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;AWS Cloud Adoption Framework (AWS CAF.), &lt;a href=&quot;https://aws.amazon.com/professional-services/CAF/&quot;&gt;https://aws.amazon.com/professional-services/CAF/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The 6 R&amp;#39;s: 6 Application Migration Strategies - AWS Cloud Enterprise Strategy Blog.), &lt;a href=&quot;https://aws.amazon.com/blogs/enterprise-strategy/6-strategies-for-migrating-applications-to-the-cloud/&quot;&gt;https://aws.amazon.com/blogs/enterprise-strategy/6-strategies-for-migrating-applications-to-the-cloud/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Well-Architected Framework.), &lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;https://aws.amazon.com/architecture/well-architected/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Migration Hub Documentation.), &lt;a href=&quot;https://aws.amazon.com/migration-hub/getting-started/&quot;&gt;https://aws.amazon.com/migration-hub/getting-started/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Modernizing with AWS: A Framework for Cloud Adoption - AWS Whitepaper.), [Search for &amp;quot;Modernizing with AWS Whitepaper&amp;quot; on aws.amazon.com/whitepapers/]&lt;/li&gt;
&lt;li&gt;Microservices on AWS - AWS Whitepaper.), [Search for &amp;quot;Microservices on AWS Whitepaper&amp;quot; on aws.amazon.com/whitepapers/]&lt;/li&gt;
&lt;li&gt;DevOps and AWS - AWS Documentation.), &lt;a href=&quot;https://aws.amazon.com/devops/what-is-devops/&quot;&gt;https://aws.amazon.com/devops/what-is-devops/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;A CIO’s guide to IT modernization&amp;quot; - McKinsey &amp;amp; Company.), &lt;a href=&quot;https://www.mckinsey.com/capabilities/mckinsey-digital/our-insights/a-cios-guide-to-it-modernization&quot;&gt;https://www.mckinsey.com/capabilities/mckinsey-digital/our-insights/a-cios-guide-to-it-modernization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;The IT Modernization Journey: From Legacy to Leading Edge&amp;quot; - Deloitte Insights.), [Search for &amp;quot;IT Modernization Deloitte&amp;quot; on deloitte.com/insights]&lt;/li&gt;
&lt;li&gt;&amp;quot;Future-Proofing Your IT Infrastructure&amp;quot; - (Example: Article from Gartner, Forrester, or a reputable tech journal.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;AWS CloudFormation Documentation.), &lt;a href=&quot;https://aws.amazon.com/cloudformation/getting-started/&quot;&gt;https://aws.amazon.com/cloudformation/getting-started/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Data Migration Service (DMS) Documentation.), &lt;a href=&quot;https://aws.amazon.com/dms/getting-started/&quot;&gt;https://aws.amazon.com/dms/getting-started/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>IT Modernization</category><category>Cloud Migration</category><category>DevOps</category><category>Business Strategy</category><category>AWS</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0061-phases-of-the-modernization-process/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Unlocking the Power of React Context API: Demystifying State Management</title><link>https://mkabumattar.com/blog/post/react-context-api-state-management/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/react-context-api-state-management/</guid><description>Explore the world of React Context API and gain insights into its use for state management. Learn how to use it to build a simple state management system.</description><pubDate>Sat, 14 Oct 2023 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the ever-evolving realm of web development, the effective management of application state is a pivotal aspect that can either elevate or hinder your project&amp;#39;s success. In this context, React, one of the most widely adopted JavaScript libraries, offers several options for state management, with the React Context API emerging as a versatile and potent tool. But what exactly is the React Context API, and how does it differ from Redux, another prominent state management library? In this blog post, we&amp;#39;ll delve into these questions and provide valuable insights into the capabilities and limitations of the React Context API.&lt;/p&gt;
&lt;h2&gt;What is Context API in React?&lt;/h2&gt;
&lt;h3&gt;Understanding the Fundamentals of Context API&lt;/h3&gt;
&lt;p&gt;The React Context API made its debut in React 16.3. It introduces a mechanism for sharing data between components without the need to manually pass props through every level of the component tree. This feature becomes exceptionally valuable in scenarios where deeply nested components require access to shared data, such as user authentication status, application themes, or language preferences.&lt;/p&gt;
&lt;p&gt;The foundation of the Context API revolves around two core components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt;: This component serves as the means to make data accessible to all descendant components. It accepts a value prop, which can be any data type, including objects or functions, that you wish to share.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Consumer&amp;gt;&lt;/code&gt;: The Consumer component facilitates the retrieval of data provided by the nearest &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; in the component hierarchy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While the data shared via Context API resembles the usage of props, it stands apart by making the shared data available globally within the context. Consequently, any component in need of this data can readily access it, without requiring explicit prop passing from parent to child.&lt;/p&gt;
&lt;h3&gt;When Should You Opt for Context API?&lt;/h3&gt;
&lt;p&gt;Now, you might be pondering why Context API should be your choice over traditional prop-passing. There are several scenarios where Context API truly shines:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Eliminating Prop Drilling&lt;/strong&gt;: Within extensive and intricate component trees, manually passing props down multiple levels can become unwieldy and error-prone. Context API streamlines this process by providing a centralized location for managing shared data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Global State Management&lt;/strong&gt;: When your application requires data access and modifications from various parts, Context API empowers you to establish a global state that is effortless to maintain and update.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Themes and Localization&lt;/strong&gt;: Context API is an excellent choice for handling themes, user preferences, and localization settings since these elements are typically needed in multiple sections of your application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: If you need to retain user authentication status and make it accessible to different parts of your application, Context API offers an effective solution.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Building a Simple State Management System with Context API&lt;/h2&gt;
&lt;h3&gt;Creating a New Next.js Project&lt;/h3&gt;
&lt;p&gt;To demonstrate the capabilities of Context API, we&amp;#39;ll build a simple state management system using Next.js. First, let&amp;#39;s create a new Next.js project by running the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# npm
npx create-next-app next-context-api

# yarn
yarn create next-app next-context-api

# pnpm
pnpx create-next-app next-context-api
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, the command-line interface will prompt you to select a template for your project. For this tutorial, we&amp;#39;ll choose &lt;code&gt;TypeScript&lt;/code&gt; as our preferred option.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;? Would you like to use TypeScript? › No / Yes # Yes
? Would you like to use ESLint? › No / Yes # Yes
? Would you like to use Tailwind CSS? › No / Yes # Yes
? Would you like to use `src/` directory? › No / Yes # Yes
? Would you like to use App Router? (recommended) › No / Yes # Yes
? Would you like to customize the default import alias (@/*)? › No / Yes # Yes
? What import alias would you like configured? › @/* # keep the default
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll also install the following one additional dependency to our project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# npm
npm install --save-dev prettier prettier-plugin-tailwindcss

# yarn
yarn add --D prettier prettier-plugin-tailwindcss

# pnpm
pnpm add --save-dev prettier prettier-plugin-tailwindcss
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the project is created, navigate to the project directory and start the development server by running the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# npm
npm run dev

# yarn
yarn dev

# pnpm
pnpm dev
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Cleaning Up the Project and Organizing the File Structure&lt;/h3&gt;
&lt;p&gt;Next, let&amp;#39;s clean up the project by removing the default files and folders that we won&amp;#39;t be using. We&amp;#39;ll also create a new folders structure to organize our project files.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Root
├── src
│   ├── app
│   │   ├── layout.tsx
│   │   └── page.tsx
│   ├── assets
│   │   ├── icons
│   │   │   └── favicon.ico
│   │   └── styles
│   │       └── globals.css
│   ├── components
│   │   ├── shared-state-child
│   │   │   └── index.tsx
│   │   ├── shared-state-grand-child
│   │   │   └── index.tsx
│   │   ├── shared-state-sibling
│   │   │   └── index.tsx
│   │   index.ts
│   └── providers
│       └── use-provider.tsx
├── .eslintrc.cjs
├── .gitignore
├── .npmrc
├── .nvmrc
├── .prettierrc.cjs
├── .yarnrc
├── next.config.mjs
├── package.json
├── postcss.config.cjs
├── README.md
├── tailwind.config.ts
├── tsconfig.json
└── yarn.lock
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;Notice type=&quot;note&quot;&gt;
  You can find the starter code for this project on [Starer
  Code](https://github.com/MKAbuMattar/next-context-api/tree/starter-code)
  branch.{&apos; &apos;}
&lt;/Notice&gt;&lt;h3&gt;Creating a Custom Provider for Context API&lt;/h3&gt;
&lt;p&gt;Now, let&amp;#39;s create a custom provider for our Context API. First, we&amp;#39;ll create a new file called &lt;code&gt;use-provider.tsx&lt;/code&gt; inside the &lt;code&gt;providers&lt;/code&gt; folder. Then, we&amp;#39;ll add the following code to this file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#39;use client&amp;#39;;

import React, {
  type ReactNode,
  type Context,
  createContext,
  useContext,
  useState,
} from &amp;#39;react&amp;#39;;

const initialContext = &amp;lt;T,&amp;gt;() =&amp;gt; new Map&amp;lt;string, T&amp;gt;();
const Context = createContext(initialContext());

type ProviderProps = {
  children: ReactNode;
};

export const Provider = ({children}: ProviderProps) =&amp;gt; (
  &amp;lt;Context.Provider value={initialContext()}&amp;gt;{children}&amp;lt;/Context.Provider&amp;gt;
);

const useContextProvider = &amp;lt;T,&amp;gt;(key: string) =&amp;gt; {
  const context = useContext(Context);
  return {
    set value(v: T) {
      context.set(key, v);
    },
    get value() {
      if (!context.has(key)) {
        throw Error(`Context key &amp;#39;${key}&amp;#39; Not Found!`);
      }
      return context.get(key) as T;
    },
  };
};

export const useProvider = &amp;lt;T,&amp;gt;(key: string, initialValue?: T) =&amp;gt; {
  const provider = useContextProvider&amp;lt;Context&amp;lt;T&amp;gt;&amp;gt;(key);
  if (initialValue !== undefined) {
    const Context = createContext&amp;lt;T&amp;gt;(initialValue);
    provider.value = Context;
  }
  return useContext(provider.value);
};

export const useSharedState = &amp;lt;T,&amp;gt;(key: string, initialValue?: T) =&amp;gt; {
  let state = undefined;
  if (initialValue !== undefined) {
    const _useState = useState;
    state = _useState(initialValue);
  }
  return useProvider(key, state);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s break down the code above to understand how it works. First, we create a new context using the &lt;code&gt;createContext&lt;/code&gt; function. Then, we create a custom hook called &lt;code&gt;useProvider&lt;/code&gt; that accepts two arguments: &lt;code&gt;key&lt;/code&gt; and &lt;code&gt;initialValue&lt;/code&gt;. The &lt;code&gt;key&lt;/code&gt; argument is used to identify the context, while the &lt;code&gt;initialValue&lt;/code&gt; argument is used to set the initial value of the context. Next, we create a custom hook called &lt;code&gt;useSharedState&lt;/code&gt; that accepts the same arguments as the &lt;code&gt;useProvider&lt;/code&gt; hook. This hook is used to create a shared state that can be accessed and modified by multiple components.&lt;/p&gt;
&lt;h3&gt;Using the Custom Provider in the Application&lt;/h3&gt;
&lt;p&gt;Now, let&amp;#39;s use the custom provider we created in the previous step in our application. First, we&amp;#39;ll import the &lt;code&gt;Provider&lt;/code&gt; component from the &lt;code&gt;use-provider.tsx&lt;/code&gt; file. Then, we&amp;#39;ll wrap the &lt;code&gt;Layout&lt;/code&gt; component with the &lt;code&gt;Provider&lt;/code&gt; component. Finally, we&amp;#39;ll add the following code to the &lt;code&gt;Layout&lt;/code&gt; component:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import &amp;#39;@/assets/styles/globals.css&amp;#39;;
// Context API
import {Provider} from &amp;#39;@/provider/use-provider&amp;#39;;
import type {Metadata} from &amp;#39;next&amp;#39;;
import {Inter} from &amp;#39;next/font/google&amp;#39;;
import React, {type ReactNode} from &amp;#39;react&amp;#39;;

const inter = Inter({subsets: [&amp;#39;latin&amp;#39;]});

export const metadata: Metadata = {
  title: &amp;#39;Next.js Context API&amp;#39;,
  description: &amp;#39;Next.js Context API example with TypeScript to manage state.&amp;#39;,
};

type RootLayoutProps = {
  children: ReactNode;
};

export default function RootLayout({children}: RootLayoutProps) {
  return (
    &amp;lt;html lang={&amp;#39;en&amp;#39;}&amp;gt;
      &amp;lt;Provider&amp;gt;
        &amp;lt;body className={inter.className}&amp;gt;{children}&amp;lt;/body&amp;gt;
      &amp;lt;/Provider&amp;gt;
    &amp;lt;/html&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Creating a Shared State&lt;/h3&gt;
&lt;p&gt;Now, let&amp;#39;s create a shared state using the &lt;code&gt;useSharedState&lt;/code&gt; hook. First, we&amp;#39;ll create a new file called &lt;code&gt;index.tsx&lt;/code&gt; inside the &lt;code&gt;components/shared-state-child&lt;/code&gt; folder. Then, we&amp;#39;ll add the following code to this file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#39;use client&amp;#39;;

// components
import {SharedStateGrandChild} from &amp;#39;@/components&amp;#39;;
// Context API
import {useSharedState} from &amp;#39;@/provider/use-provider&amp;#39;;
import React, {Fragment} from &amp;#39;react&amp;#39;;

export const SharedStateChild = () =&amp;gt; {
  const [count] = useSharedState&amp;lt;number&amp;gt;(&amp;#39;count&amp;#39;);

  return (
    &amp;lt;Fragment&amp;gt;
      &amp;lt;p className={&amp;#39;text-center text-xl font-semibold&amp;#39;}&amp;gt;
        Shared State Child: {count}
      &amp;lt;/p&amp;gt;
      &amp;lt;SharedStateGrandChild /&amp;gt;
    &amp;lt;/Fragment&amp;gt;
  );
};

export default SharedStateChild;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we&amp;#39;ll create a new file called &lt;code&gt;index.tsx&lt;/code&gt; inside the &lt;code&gt;components/shared-state-grand-child&lt;/code&gt; folder. Then, we&amp;#39;ll add the following code to this file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#39;use client&amp;#39;;

// Context API
import {useSharedState} from &amp;#39;@/provider/use-provider&amp;#39;;
import React, {Fragment} from &amp;#39;react&amp;#39;;

export const SharedStateGrandChild = () =&amp;gt; {
  const [count] = useSharedState&amp;lt;number&amp;gt;(&amp;#39;count&amp;#39;);

  return (
    &amp;lt;Fragment&amp;gt;
      &amp;lt;p className={&amp;#39;text-center text-xl font-semibold&amp;#39;}&amp;gt;
        Shared State Grand Child: {count}
      &amp;lt;/p&amp;gt;
    &amp;lt;/Fragment&amp;gt;
  );
};

export default SharedStateGrandChild;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we&amp;#39;ll create a new file called &lt;code&gt;index.tsx&lt;/code&gt; inside the &lt;code&gt;components/shared-state-sibling&lt;/code&gt; folder. Then, we&amp;#39;ll add the following code to this file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#39;use client&amp;#39;;

// Context API
import {useSharedState} from &amp;#39;@/provider/use-provider&amp;#39;;
import React, {Fragment} from &amp;#39;react&amp;#39;;

export const SharedStateSibling = () =&amp;gt; {
  const [count] = useSharedState&amp;lt;number&amp;gt;(&amp;#39;count&amp;#39;);

  return (
    &amp;lt;Fragment&amp;gt;
      &amp;lt;p className={&amp;#39;text-center text-xl font-semibold&amp;#39;}&amp;gt;
        Shared State Sibling: {count}
      &amp;lt;/p&amp;gt;
    &amp;lt;/Fragment&amp;gt;
  );
};

export default SharedStateSibling;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating a &lt;code&gt;index.ts&lt;/code&gt; file inside the &lt;code&gt;components&lt;/code&gt; folder and adding the following code to it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;export {default as SharedStateChild} from &amp;#39;@/components/shared-state-child&amp;#39;;
export {default as SharedStateGrandChild} from &amp;#39;@/components/shared-state-grand-child&amp;#39;;
export {default as SharedStateSibling} from &amp;#39;@/components/shared-state-sibling&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Updating the Shared State from the Parent Component/Page&lt;/h3&gt;
&lt;p&gt;Now, let&amp;#39;s update the shared state from the parent component. First, we&amp;#39;ll create a new file called &lt;code&gt;index.tsx&lt;/code&gt; inside the &lt;code&gt;app&lt;/code&gt; folder. Then, we&amp;#39;ll add the following code to this file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;#39;use client&amp;#39;;

// Context API
// components
import {SharedStateChild, SharedStateSibling} from &amp;#39;@/components&amp;#39;;
import {useSharedState} from &amp;#39;@/provider/use-provider&amp;#39;;

export default function Home() {
  const [_, setCount] = useSharedState&amp;lt;number&amp;gt;(&amp;#39;count&amp;#39;, 0);

  const increment = () =&amp;gt; setCount((prev) =&amp;gt; prev + 1);
  const decrement = () =&amp;gt; setCount((prev) =&amp;gt; prev - 1);
  const reset = () =&amp;gt; setCount(0);

  return (
    &amp;lt;main className={&amp;#39;flex h-screen flex-col items-center justify-center&amp;#39;}&amp;gt;
      &amp;lt;h1 className={&amp;#39;text-center text-4xl font-bold&amp;#39;}&amp;gt;Next.js Context API&amp;lt;/h1&amp;gt;

      &amp;lt;p className={&amp;#39;text-center text-xl font-semibold&amp;#39;}&amp;gt;
        Count Example with Context API and TypeScript
      &amp;lt;/p&amp;gt;

      &amp;lt;div className={&amp;#39;mt-8 flex flex-col items-center justify-center gap-4&amp;#39;}&amp;gt;
        &amp;lt;SharedStateChild /&amp;gt;
        &amp;lt;SharedStateSibling /&amp;gt;
        &amp;lt;div className={&amp;#39;flex flex-row items-center justify-center gap-4&amp;#39;}&amp;gt;
          &amp;lt;button
            type={&amp;#39;button&amp;#39;}
            className={
              &amp;#39;rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700&amp;#39;
            }
            onClick={increment}
          &amp;gt;
            Increment
          &amp;lt;/button&amp;gt;
          &amp;lt;button
            type={&amp;#39;button&amp;#39;}
            className={
              &amp;#39;rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700&amp;#39;
            }
            onClick={decrement}
          &amp;gt;
            Decrement
          &amp;lt;/button&amp;gt;
          &amp;lt;button
            type={&amp;#39;button&amp;#39;}
            className={
              &amp;#39;rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700&amp;#39;
            }
            onClick={reset}
          &amp;gt;
            Reset
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/main&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Testing the Application&lt;/h3&gt;
&lt;p&gt;Finally, let&amp;#39;s test the application by running the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# npm
npm run dev

# yarn
yarn dev

# pnpm
pnpm dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If everything works as expected, you should see the following output:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0060-react-context-api-state-management/next-context-api-example.png&quot; alt=&quot;Next.js Context API Example&quot;&gt;&lt;/p&gt;
&lt;Notice type=&quot;note&quot;&gt;
  You can find the final code for this project on [Final
  Code](https://github.com/MKAbuMattar/next-context-api) branch.
&lt;/Notice&gt;&lt;h2&gt;Is Context API the Same as Redux?&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;Contrasting React Context API with Redux&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Redux, a widely acknowledged state management library, has enjoyed substantial adoption in React applications. It provides a structured and centralized method for managing application state. So, is Context API merely a Redux alternative? Let&amp;#39;s uncover the disparities between these two state management solutions.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complexity&lt;/strong&gt;: Redux is renowned for its rigid architectural principles, which can serve as both a strength and a limitation. It enforces a unidirectional data flow and mandates the use of actions and reducers. While this is advantageous for larger applications, it might seem excessive for smaller projects. In contrast, Context API is lightweight and flexible, offering a simpler entry point, making it ideal for applications with modest state management requirements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ecosystem&lt;/strong&gt;: Redux boasts a mature ecosystem with a wide array of extensions, middleware, and developer tools. It has been rigorously tested in the field and enjoys a sizable community, providing solutions for a multitude of issues. On the other hand, while Context API is gaining popularity, its ecosystem is not as extensive. If you require a comprehensive solution, Redux remains the preferred choice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;: Redux excels in performance optimization through mechanisms like memoization and efficient state updates. Context API, in its basic form, might not offer the same degree of optimization. Nevertheless, by employing memoization libraries such as reselect and useMemo, you can attain solid performance with Context API as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;: Redux presents a steeper learning curve due to its strict conventions and associated boilerplate code. Context API, conversely, is more approachable, particularly for developers who are new to state management in React. If you seek a swift and uncomplicated state management solution, Context API stands out.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State Size&lt;/strong&gt;: For applications with extensive and intricate state structures, Redux provides a transparent and comprehensive approach through reducers and actions. Context API is more apt for applications with smaller and less intricate state management needs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Selecting the Right Tool&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The choice between Context API and Redux hinges on the particular demands of your application. If you are working on a modest to medium-sized project and favor simplicity and a shorter learning curve, Context API is an outstanding choice. On the other hand, for large-scale applications with complex state management requisites and an appreciation for a mature ecosystem, Redux remains the better option. In some cases, a blend of both could prove to be the most beneficial, with Context API addressing simpler local state management within specific components, and Redux handling overarching application state management.&lt;/p&gt;
&lt;h2&gt;What is the Problem with Context API in React?&lt;/h2&gt;
&lt;h3&gt;Understanding the Limitations of Context API&lt;/h3&gt;
&lt;p&gt;While the React Context API is a powerful tool for state management, it does have its limitations. Let&amp;#39;s delve into some of the challenges you might encounter when using Context API.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Propagation of Updates&lt;/strong&gt;: Context API triggers a re-render of all components consuming the context each time the provider&amp;#39;s value changes. This can pose an issue in cases where you have a deep component tree, leading to unnecessary re-renders. You can alleviate this problem by employing memoization techniques and optimizing components.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of Built-in Middleware&lt;/strong&gt;: Redux offers middleware for managing side effects and asynchronous actions, which are crucial in many applications. Context API does not include built-in middleware, necessitating the use of additional libraries or custom solutions for handling side effects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debugging Tools&lt;/strong&gt;: Redux offers an extensive suite of developer tools that prove invaluable when debugging your application. While Context API does feature some developer tools, they may not offer the same level of support, making it somewhat more challenging to trace data flow and debug issues.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Global vs. Local State&lt;/strong&gt;: Context API is primarily designed for sharing global state. If your application requires components with local state that shouldn&amp;#39;t be shared with the entire application, managing such cases can be less straightforward with Context API. Redux, with its capability for local component state, provides greater control in such scenarios.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handling Complex State&lt;/strong&gt;: For applications featuring complex state structures, Redux&amp;#39;s reducers and actions offer a clear and structured approach. Context API might require additional coding to manage complex states effectively.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Frequently Asked Questions on Context API&lt;/h2&gt;
&lt;p&gt;Now that we&amp;#39;ve explored the fundamentals, compared Context API with Redux, and discussed its limitations, let&amp;#39;s address some common questions related to the React Context API:&lt;/p&gt;
&lt;h3&gt;Can Context API Replace Redux for Large Applications?&lt;/h3&gt;
&lt;p&gt;While technically possible, using Context API for extensive applications might not be the most suitable choice. Redux&amp;#39;s architecture, middleware, and developer tools are better equipped to handle the complexity often encountered in large applications.&lt;/p&gt;
&lt;h3&gt;Can Context API and Redux Coexist in the Same Application?&lt;/h3&gt;
&lt;p&gt;Certainly, you can utilize both Context API and Redux within a single application. Context API can effectively manage simpler local state requirements within specific components, while Redux can oversee global state management and complex state structures.&lt;/p&gt;
&lt;h3&gt;What Are Some Typical Use Cases for Context API?&lt;/h3&gt;
&lt;p&gt;Context API excels in managing global application state, including tasks like user authentication, theme management, and localization. It&amp;#39;s also a valuable tool for eliminating the need for prop drilling in deeply nested component structures.&lt;/p&gt;
&lt;h3&gt;Has Redux Become Obsolete with the Introduction of Context API?&lt;/h3&gt;
&lt;p&gt;Redux has not become obsolete. It remains a valuable tool, particularly for extensive applications with intricate state management requirements. Context API, while more lightweight and beginner-friendly, serves as an alternative rather than a replacement.&lt;/p&gt;
&lt;h3&gt;Can Functions and Methods be Shared via Context API?&lt;/h3&gt;
&lt;p&gt;Indeed, Context API allows you to share functions and methods, making it a versatile choice for sharing not just data but also behaviors across components.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The React Context API is a valuable addition to the array of state management tools available in React. It streamlines the sharing of data between components, eliminates the need for prop drilling, and efficiently manages global application state. Although it may not supplant Redux in all use cases, it provides a more accessible and lightweight alternative, especially for smaller projects and those with less complex state management requirements.&lt;/p&gt;
&lt;p&gt;As a software engineer, comprehending the strengths and limitations of the tools at your disposal is crucial. Context API is a valuable addition to your toolkit, and by thoughtfully evaluating your project&amp;#39;s requirements, you can make the right choice, whether it&amp;#39;s Context API, Redux, or a combination of both.&lt;/p&gt;
&lt;p&gt;The world of web development is dynamic, and staying updated with the latest tools and best practices is imperative. Context API represents just one piece of the puzzle, yet mastering it can unlock new possibilities for your React applications.&lt;/p&gt;
&lt;p&gt;So, what&amp;#39;s your next step? Will you venture deeper into the intricacies of React Context API, leveraging its capabilities to construct more efficient and maintainable applications? Alternatively, will you remain loyal to Redux, or perhaps explore different state management solutions? The choice is yours, and your journey as a software engineer is guided by your expertise, enabling you to navigate the ever-evolving landscape of web development.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/learn/passing-data-deeply-with-context&quot;&gt;React Context API - Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redux.js.org/&quot;&gt;Redux - Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.logrocket.com/react-context-api-vs-redux/&quot;&gt;When to Use React Context vs. Redux - LogRocket Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freecodecamp.org/news/react-context-api-a-complete-guide/&quot;&gt;A Guide to React Context API - freeCodeCamp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.taniarascia.com/using-context-api-in-react/&quot;&gt;Managing State in React with Context API and Hooks - Tania Rascia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/docs/pages/building-your-application/data-fetching/forms-and-mutations#managing-form-state&quot;&gt;Next.js Documentation - State Management&lt;/a&gt; (Note: Next.js docs might not directly cover Context API in depth for global state, but it&amp;#39;s relevant for Next.js projects)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.robinwieruch.de/react-typescript-context/&quot;&gt;TypeScript with React Context API - Robin Wieruch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/react-usecontext&quot;&gt;Understanding &lt;code&gt;useContext&lt;/code&gt; Hook in React - DigitalOcean&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.simform.com/blog/react-context-api-vs-redux/&quot;&gt;React Context API vs Redux: Which One Should You Choose? - Simform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kentcdodds.com/blog/application-state-management-with-react&quot;&gt;State Management with React Context and Hooks - Kent C. Dodds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/swlh/avoiding-prop-drilling-in-react-with-context-api-8c00768e95e&quot;&gt;Avoiding Prop Drilling in React with Context API - Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.developerway.com/posts/how-to-write-performant-react-apps-with-context&quot;&gt;Performance Considerations for React Context API - (Example: Search for articles on this topic from reputable sources like LogRocket, Smashing Magazine, or dev.to)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>ReactJS</category><category>State Management</category><category>Frontend Development</category><category>Next.js</category><category>JavaScript</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0060-react-context-api-state-management/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Becoming an AWS Pro: A Deep Dive into Amazon Elastic Container Service</title><link>https://mkabumattar.com/blog/post/aws-ecs-deep-dive/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/aws-ecs-deep-dive/</guid><description>Ready to elevate your AWS DevOps skills with Amazon Elastic Container Service? Explore ECS versus EC2, discover its versatile use cases, and embark on a journey from traditional on-premises servers to EC2 instances, and finally to the seamless world of ECS Fargate.</description><pubDate>Fri, 13 Oct 2023 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Are you a passionate AWS Cloud Engineer DevOps enthusiast, looking to sharpen your container orchestration skills and level up your cloud infrastructure management game? Amazon Elastic Container Service (ECS) is your key to unlocking a world of possibilities. In this in-depth guide, we&amp;#39;ll delve into the heart of ECS, addressing the most common questions that arise in this exciting domain.&lt;/p&gt;
&lt;h2&gt;What is ECS and EC2?&lt;/h2&gt;
&lt;p&gt;To begin, let&amp;#39;s tackle the fundamental question: What is Amazon Elastic Container Service (ECS), and how does it tie into Elastic Compute Cloud (EC2)?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Amazon Elastic Container Service (ECS)&lt;/strong&gt; stands as a fully-managed container orchestration service designed to simplify the running, stopping, and management of Docker containers on a cluster of EC2 instances. It streamlines container deployment and scaling while maintaining robust security and high availability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elastic Compute Cloud (EC2)&lt;/strong&gt;, on the other hand, offers scalable cloud-based compute resources. It provides a diverse range of instance types, each optimized for various use cases. EC2 instances essentially serve as virtual servers in the cloud, capable of running multiple operating systems.&lt;/p&gt;
&lt;p&gt;The connection between ECS and EC2 is clear: ECS leverages EC2 instances as the backbone for efficiently deploying and managing containerized applications. For DevOps professionals, ECS is a potent tool in the realm of containerization and orchestration.&lt;/p&gt;
&lt;h2&gt;What is the Difference between EKS and ECS?&lt;/h2&gt;
&lt;p&gt;You may have come across Amazon Elastic Kubernetes Service (EKS) and wonder how ECS sets itself apart. Let&amp;#39;s demystify the distinction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Amazon Elastic Kubernetes Service (EKS)&lt;/strong&gt; is yet another managed container orchestration service, but it is tailored for orchestrating Kubernetes clusters. Kubernetes, being an open-source container orchestration platform, has gained immense popularity. EKS offers a managed Kubernetes control plane and simplifies the deployment, management, and scaling of containerized applications using Kubernetes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Amazon Elastic Container Service (ECS)&lt;/strong&gt;, as we discussed earlier, offers a similar service but is focused on Docker containers. The primary differentiator lies in the underlying orchestration system; ECS employs its proprietary system, while EKS relies on Kubernetes.&lt;/p&gt;
&lt;p&gt;The choice between ECS and EKS is contingent on your specific requirements and your familiarity with Kubernetes. ECS is often a more straightforward choice for those deeply entrenched in the AWS ecosystem, seeking an efficient containerization solution.&lt;/p&gt;
&lt;h2&gt;What is Amazon Elastic Container Service Used to Deploy?&lt;/h2&gt;
&lt;p&gt;ECS isn&amp;#39;t just a buzzword; it&amp;#39;s a versatile workhorse capable of deploying a wide spectrum of applications. But what exactly can you accomplish with ECS? Let&amp;#39;s explore its diverse applications.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Web Applications&lt;/strong&gt;: ECS is an excellent choice for deploying web applications that need to dynamically scale with varying traffic loads. Whether it&amp;#39;s a simple blog or a sophisticated e-commerce platform, ECS is up for the task.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Microservices&lt;/strong&gt;: If your architectural framework relies on microservices, ECS offers a simplified approach to managing these small, independently deployable components.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Batch Processing&lt;/strong&gt;: For processing substantial volumes of data in batch operations, ECS is a proficient solution, enabling efficient execution of batch jobs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stateful Applications&lt;/strong&gt;: ECS seamlessly supports both stateless and stateful applications, ensuring adaptability for diverse use cases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Machine Learning&lt;/strong&gt;: If you&amp;#39;re running machine learning models within containers, ECS excels in the management of the containers where your models operate.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What is Elastic Container Service AWS?
Amazon Elastic Container Service (ECS) is an integral part of the AWS ecosystem, but what makes it stand out among other container orchestration solutions? Let&amp;#39;s uncover the key features that make ECS a standout choice for AWS DevOps engineers.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Easy Cluster Management&lt;/strong&gt;: ECS abstracts the complexities of infrastructure management. You focus on defining your containerized applications, and ECS takes care of the rest.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High Availability&lt;/strong&gt;: ECS optimizes high availability and fault tolerance by distributing containers across multiple Availability Zones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration with AWS Services&lt;/strong&gt;: ECS seamlessly integrates with other AWS services like Elastic Load Balancing, Identity and Access Management (IAM), and CloudWatch for comprehensive monitoring.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Task Definitions&lt;/strong&gt;: ECS provides the flexibility to define container configurations, making it effortless to specify resources, dependencies, and environment variables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto Scaling&lt;/strong&gt;: ECS is equipped to automatically scale your application, whether up or down, in accordance with predefined policies, ensuring optimal resource utilization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: ECS offers robust security measures, including the use of IAM roles and resource-based policies to regulate access to your ECS resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost Optimization&lt;/strong&gt;: ECS&amp;#39;s resource-based billing model ensures you pay only for the resources you actively utilize, leading to cost efficiency.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;From On-Premises Server to EC2 Instance to ECS Fargate&lt;/h2&gt;
&lt;p&gt;Now, let&amp;#39;s embark on a hands-on journey, transitioning from conventional on-premises servers to Amazon EC2 instances, and finally embracing the seamless world of AWS ECS Fargate. This practical example will illuminate how ECS fits into the grand scheme of container orchestration.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;On-Premises Servers&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Imagine you have a traditional on-premises server environment where your applications run directly on physical servers. While this is a conventional setup, it may lack the scalability, agility, and management ease that cloud-based solutions provide.&lt;/p&gt;
&lt;h3&gt;Amazon EC2 Instances&lt;/h3&gt;
&lt;p&gt;To modernize your infrastructure, you decide to migrate to AWS, beginning with Amazon EC2 instances. EC2 offers virtual cloud servers, making the transition a natural progression. You can replicate your on-premises servers as EC2 instances, granting you the flexibility to resize them, experiment with different instance types, and leverage the array of AWS services.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a simplified roadmap:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create an EC2 Instance&lt;/strong&gt;: Initiate the launch of an EC2 instance with your desired operating system and instance type.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Install Docker&lt;/strong&gt;: Prepare your EC2 instance for containerized applications by installing Docker.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Containerize Your Application&lt;/strong&gt;: Package your application and its dependencies into Docker containers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run Containers on EC2&lt;/strong&gt;: Deploy your containers on the EC2 instance using Docker.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While this approach offers the benefits of running applications within containers on EC2, it entails manual management of instances, scaling considerations, and maintaining high availability.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;AWS Elastic Container Service (ECS)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To fully harness the power of container orchestration, you decide to transition from running containers on EC2 instances to utilizing ECS, particularly ECS Fargate. Fargate, being a serverless compute engine for containers, eliminates the need to manage the underlying EC2 instances.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how the transition unfolds:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create an ECS Cluster&lt;/strong&gt;: Within ECS, you form a cluster that serves as the container group.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Define Task Definitions&lt;/strong&gt;: Task definitions outline the configuration of your containers, encompassing resource allocation, dependencies, and environmental variables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Launch Tasks&lt;/strong&gt;: You initiate tasks within your ECS cluster. ECS Fargate takes on the heavy lifting of provisioning infrastructure, allowing you to solely focus on your application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto Scaling&lt;/strong&gt;: ECS Fargate offers automated scaling of the number of tasks, in line with your defined policies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High Availability&lt;/strong&gt;: ECS Fargate guarantees high availability by dispersing tasks across various Availability Zones.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This transition streamlines infrastructure management, enhances scalability, and empowers you to prioritize your application development over managing the underlying instances.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;p&gt;Now that we&amp;#39;ve covered the essentials and walked through a practical example, it&amp;#39;s time to address some of the most frequently asked questions about Amazon Elastic Container Service:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is Amazon ECS suitable for small-scale applications?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Certainly! ECS is highly adaptable and can accommodate applications of all sizes. Whether you&amp;#39;re running a compact website or a complex microservices architecture, ECS can seamlessly scale to meet your needs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How does ECS pricing work?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ECS pricing hinges on the resources you consume, including EC2 instances, Fargate tasks, and data transfer. The pay-as-you-go model ensures that you only pay for what you actively use, making it a cost-effective choice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&amp;#39;s the learning curve for AWS ECS?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The learning curve for AWS ECS can vary, contingent on your prior experience with containerization and AWS. Nonetheless, the abundance of documentation and the user-friendly AWS interface means you can quickly acclimate to ECS&amp;#39;s functionalities.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I use container runtimes other than Docker with ECS?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Absolutely. ECS offers flexibility by supporting alternative container runtimes such as containerd, accommodating a range of containerization needs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I monitor ECS tasks and services?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AWS provides an extensive monitoring solution through Amazon CloudWatch, enabling you to closely monitor your ECS clusters, tasks, and services.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Amazon Elastic Container Service emerges as a pivotal tool for cloud engineers and DevOps professionals. Its simplicity, scalability, and seamless integration with other AWS services position it as a robust choice for managing containerized applications. As you embark on your ECS journey, remember to assess your specific use case, whether you&amp;#39;re transitioning from on-premises servers or optimizing your existing AWS infrastructure.&lt;/p&gt;
&lt;p&gt;With ECS at your disposal, you gain the capability to orchestrate containers with elegance and ease. Your containerized applications will thrive, and your operational efficiency will reach new heights.&lt;/p&gt;
&lt;p&gt;Intrigued by ECS? Dive deeper and unlock the full potential of your containerized workloads within the AWS ecosystem.&lt;/p&gt;
&lt;p&gt;Regardless of whether you&amp;#39;re a newcomer to AWS or a seasoned cloud engineer, there&amp;#39;s always more to explore and discover. If you have questions or experiences to share concerning Amazon ECS, don&amp;#39;t hesitate to leave a comment below. Let&amp;#39;s continue the conversation!&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/ecs/&quot;&gt;Amazon Elastic Container Service (ECS) - Official Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/eks/&quot;&gt;Amazon Elastic Kubernetes Service (EKS) - Official Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/ec2/&quot;&gt;Amazon EC2 - Official Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/fargate/&quot;&gt;AWS Fargate - Official Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html&quot;&gt;What is Amazon ECS? - AWS Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/comparing-eks-ecs/comparing-eks-ecs.html&quot;&gt;Comparing Amazon ECS and Amazon EKS - AWS Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/ecs/features/&quot;&gt;Amazon ECS Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/ecs/pricing/&quot;&gt;Amazon ECS Pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/ecs/faqs/&quot;&gt;Amazon ECS FAQs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://catalog.workshops.aws/ecs-fargate-introduction/en-US&quot;&gt;Getting Started with Amazon ECS using Fargate - AWS Workshop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/bestpracticesguide/introduction.html&quot;&gt;Best Practices for Amazon ECS - AWS Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/docker/&quot;&gt;Docker on AWS&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AWS</category><category>Cloud Computing</category><category>DevOps</category><category>Containerization</category><category>ECS</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0059-aws-ecs-deep-dive/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Building a Code Generative AI Model: Empowering Code Writing with AI</title><link>https://mkabumattar.com/blog/post/building-a-code-generative-ai-model-empowering-code-writing-with-ai/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/building-a-code-generative-ai-model-empowering-code-writing-with-ai/</guid><description>Explore the process of building a Code Generative AI model as a software engineer. Understand how AI can write code, follow step-by-step instructions to create your AI, and find answers to common queries about AI-generated code.</description><pubDate>Tue, 29 Aug 2023 00:08:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the ever-evolving landscape of software engineering, automation stands as a cornerstone. As a software engineer, have you ever envisioned having an AI companion capable of crafting code snippets, lightening your workload? The good news is that this vision is no longer confined to dreams. Thanks to the emergence of Code Generative AI, you can now tap into the potential of artificial intelligence to write code on your behalf. In this article, we will embark on a journey to construct your very own Code Generative AI model while addressing some pertinent questions along the way.&lt;/p&gt;
&lt;h2&gt;Can Generative AI Write Code?&lt;/h2&gt;
&lt;p&gt;Before we delve into the intricacies, let&amp;#39;s confront a fundamental question: can Generative AI genuinely write code? In short, yes, it can. Generative AI models, particularly those founded on neural networks, have demonstrated astonishing capabilities in generating human-like text, including code. These models undergo rigorous training on extensive datasets encompassing various programming languages, enabling them to produce code snippets that are not only syntactically accurate but also semantically meaningful.&lt;/p&gt;
&lt;h2&gt;What is Generative AI Computer Code?&lt;/h2&gt;
&lt;p&gt;Generative AI computer code refers to code generated by artificial intelligence models, such as neural networks, using natural language prompts. These models have acquired the nuances and structures of code through extensive training data, enabling them to produce code that closely resembles what a human programmer might write. This generated code can encompass anything from simple functions to intricate algorithms, contingent on the prompt and the model&amp;#39;s training.&lt;/p&gt;
&lt;h2&gt;How Do I Create a Generative AI for Code?&lt;/h2&gt;
&lt;p&gt;Now, let&amp;#39;s venture into the practical steps involved in constructing your Code Generative AI model. We will dissect the process step by step, making it accessible for you to create your very own AI code-writing assistant.&lt;/p&gt;
&lt;h3&gt;Step 1: Environment Setup&lt;/h3&gt;
&lt;p&gt;To commence your journey, you&amp;#39;ll need a Python environment equipped with the requisite libraries and dependencies. In the following code snippet, we have laid out a fundamental setup for your AI model, complete with imports and configuration settings:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import logging
import torch
import peft
import transformers
from transformers import AutoTokenizer, AutoModelForCausalLM
from huggingface_hub.hf_api import HfFolder

# Configuration class for the Dumpster Copilot Generative model
class Configuration:
    ACCESS_TOKEN = &amp;#39;ENTER YOUR HUGGINGFACE ACCESS TOKEN HERE&amp;#39;
    LOAD_IN_8BIT = False
    BASE_MODEL = &amp;#39;meta-llama/Llama-2-7b-chat-hf&amp;#39;
    LORA_WEIGHTS = &amp;#39;qblocks/llama2-7b-tiny-codes-code-generation&amp;#39;
    PROMPT = &amp;#39;Write a Python function to divide 2 numbers and check for division by zero.&amp;#39;

# Exception classes for errors loading the model and generating text
class ModelLoadingError(Exception):
    pass

class DumpsterCopilotGenerativeError(Exception):
    pass

# Model loader class
class ModelLoader:
    @staticmethod
    def load_model() -&amp;gt; tuple:
        try:
            tokenizer = AutoTokenizer.from_pretrained(Configuration.LORA_WEIGHTS)
            model = AutoModelForCausalLM.from_pretrained(
                Configuration.BASE_MODEL,
                device_map=&amp;#39;auto&amp;#39;,
                torch_dtype=torch.float16,
                load_in_8bit=Configuration.LOAD_IN_8BIT
            )
            model = peft.PeftModel.from_pretrained(model, Configuration.LORA_WEIGHTS)
            return tokenizer, model
        except Exception as e:
            raise ModelLoadingError(f&amp;#39;Error loading tokenizer and model: {str(e)}&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this code snippet, we&amp;#39;ve imported essential libraries like &lt;code&gt;transformers&lt;/code&gt; and &lt;code&gt;torch&lt;/code&gt;, and we&amp;#39;ve introduced a &lt;code&gt;Configuration&lt;/code&gt; class to house critical settings. You&amp;#39;ll also notice the &lt;code&gt;ModelLoader&lt;/code&gt; class, which is responsible for loading the AI model.&lt;/p&gt;
&lt;h3&gt;Step 2: Loading Your AI Model&lt;/h3&gt;
&lt;p&gt;Now that your environment is set up, it&amp;#39;s time to load your Code Generative AI model. In the code snippet, we&amp;#39;ve defined a &lt;code&gt;ModelLoader&lt;/code&gt; class with a &lt;code&gt;load_model&lt;/code&gt; method designed to handle model loading. This method returns a tokenizer and a model instance. Remember to replace &lt;code&gt;&amp;#39;ENTER YOUR HUGGINGFACE ACCESS TOKEN HERE&amp;#39;&lt;/code&gt; with your actual Hugging Face access token.&lt;/p&gt;
&lt;h3&gt;Step 3: Generating Code with Your AI&lt;/h3&gt;
&lt;p&gt;With your model loaded, you&amp;#39;re poised to generate code snippets with your AI assistant. We&amp;#39;ve provided a &lt;code&gt;DumpsterCopilotGenerative&lt;/code&gt; class that streamlines the code generation process based on a provided prompt:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;class DumpsterCopilotGenerative:
    def __init__(self, tokenizer, model):
        self.tokenizer = tokenizer
        self.model = model

    def dumpster_copilot_generative(self, prompt: str) -&amp;gt; str:
        try:
            logging.info(f&amp;#39;Generating text for prompt: {prompt}&amp;#39;)

            generator = transformers.pipeline(
                &amp;#39;text-generation&amp;#39;,
                model=self.model,
                tokenizer=self.tokenizer
            )

            generation_config = transformers.GenerationConfig(
                temperature=0.4,
                top_p=0.99,
                top_k=40,
                num_beams=2,
                max_new_tokens=400,
                repetition_penalty=1.3
            )

            t = generator(prompt, generation_config=generation_config)

            generated_text = t[0][&amp;#39;generated_text&amp;#39;]

            logging.info(f&amp;#39;Generated text: {generated_text}&amp;#39;)
            return generated_text
        except Exception as e:
            raise DumpsterCopilotGenerativeError(f&amp;#39;Error generating text: {str(e)}&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This class incorporates a &lt;code&gt;dumpster_copilot_generative&lt;/code&gt; method, which accepts a prompt as input and furnishes the generated code as output. The code generated hinges on the provided prompt, so ensure that your prompt is explicit and specific.&lt;/p&gt;
&lt;h3&gt;Step 4: Running Your Code Generative AI&lt;/h3&gt;
&lt;p&gt;Now that all the elements are in place, you can set your Code Generative AI model in motion to generate code. Here&amp;#39;s an illustration of how you can achieve this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;if __name__ == &amp;#39;__main__&amp;#39;:
    try:
        if Configuration.ACCESS_TOKEN:
            HfFolder.save_token(Configuration.ACCESS_TOKEN)

        logging.info(&amp;#39;Initiating the text generation process.&amp;#39;)

        tokenizer, model = ModelLoader.load_model()
        generator = DumpsterCopilotGenerative(tokenizer, model)
        generated_text = generator.dumpster_copilot_generative(Configuration.PROMPT)

        logging.info(&amp;#39;Generated text:&amp;#39;)
        logging.info(generated_text)

        logging.info(&amp;#39;Successful completion of the text generation process.&amp;#39;)
    except (ModelLoadingError, DumpsterCopilotGenerativeError) as e:
        logging.error(f&amp;#39;An error occurred: {str(e)}&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This central block of code initializes your AI model, generates code grounded in the provided prompt (in this instance, &amp;quot;Write a Python function to divide 2 numbers and check for division by zero.&amp;quot;), and logs the resulting code.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;p&gt;Now that you have a foundational grasp of constructing a Code Generative AI model, let&amp;#39;s address some frequently posed questions:&lt;/p&gt;
&lt;h3&gt;Q1: How does Generative AI comprehend programming languages?&lt;/h3&gt;
&lt;p&gt;Generative AI models acquire an understanding of programming languages through extensive training on code written in various programming languages. They absorb the syntax, semantics, and patterns of code from diverse datasets, allowing them to generate code that conforms to the conventions of specific programming languages.&lt;/p&gt;
&lt;h3&gt;Q2: Can Generative AI replace human programmers?&lt;/h3&gt;
&lt;p&gt;Generative AI can automate specific facets of coding, such as producing boilerplate code or facilitating code completion. However, it does not replace human programmers. Human expertise remains indispensable for conceiving intricate algorithms, debugging, and making pivotal decisions in the realm of software development.&lt;/p&gt;
&lt;h3&gt;Q3: Are there ethical concerns related to AI-generated code?&lt;/h3&gt;
&lt;p&gt;Indeed, there exist ethical concerns associated with AI-generated code. These concerns encompass the potential for bias in the training data and the misuse of AI-generated code for nefarious purposes. It is imperative to employ AI-generated code judiciously and ensure that it aligns with ethical standards.&lt;/p&gt;
&lt;h3&gt;Q4: What are some practical applications of Code Generative AI?&lt;/h3&gt;
&lt;p&gt;Code Generative AI finds utility in a myriad of practical applications, including code autocompletion, code refactoring, the generation of documentation, and assistance in code reviews. It can significantly enhance developer productivity and contribute to the enhancement of code quality.&lt;/p&gt;
&lt;h3&gt;Q5: How can I fine-tune my Code Generative AI model?&lt;/h3&gt;
&lt;p&gt;Fine-tuning a Code Generative AI model involves training it on specific datasets or within particular domains to enhance its specialization. Existing models can be fine-tuned through the utilization of transfer learning techniques and domain-specific data.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the domain of software engineering, the integration of AI, particularly Code Generative AI, holds the potential to revolutionize code writing. By following the steps elucidated in this article, you can fashion your very own Code Generative AI model to assist you in your coding pursuits. However, it is crucial to bear in mind that while AI constitutes a potent tool, human expertise and ethical considerations should perpetually guide software development.&lt;/p&gt;
&lt;p&gt;The journey of crafting your Code Generative AI is a thrilling one, opening up novel possibilities in the sphere of software engineering. So, are you prepared to embark on this coding voyage with AI as your trusty companion?&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Hugging Face Transformers Documentation.), &lt;a href=&quot;https://huggingface.co/docs/transformers/index&quot;&gt;https://huggingface.co/docs/transformers/index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PEFT - Parameter-Efficient Fine-Tuning of Billion-Scale Models on Low-Resource Hardware.), &lt;a href=&quot;https://github.com/huggingface/peft&quot;&gt;https://github.com/huggingface/peft&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Llama 2 - Meta AI.), &lt;a href=&quot;https://ai.meta.com/llama/&quot;&gt;https://ai.meta.com/llama/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Attention Is All You Need&amp;quot; (Transformer paper) - Vaswani, A., et al. (2017.), &lt;a href=&quot;https://arxiv.org/abs/1706.03762&quot;&gt;https://arxiv.org/abs/1706.03762&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Language Models are Unsupervised Multitask Learners&amp;quot; (GPT-2 paper) - Radford, A., et al.), [Link to OpenAI&amp;#39;s GPT-2 paper or blog post]&lt;/li&gt;
&lt;li&gt;&amp;quot;Evaluating Large Language Models Trained on Code&amp;quot; - Chen, M., et al. (OpenAI Codex.), &lt;a href=&quot;https://arxiv.org/abs/2107.03374&quot;&gt;https://arxiv.org/abs/2107.03374&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hugging Face Model Hub.), &lt;a href=&quot;https://huggingface.co/models&quot;&gt;https://huggingface.co/models&lt;/a&gt; (Specifically search for code generation models like &lt;code&gt;meta-llama/Llama-2-7b-chat-hf&lt;/code&gt; and &lt;code&gt;qblocks/llama2-7b-tiny-codes-code-generation&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&amp;quot;The Ethical Implications of Code Generation AI&amp;quot; - (Example: Article from IEEE Spectrum, MIT Technology Review, or a similar publication.), [Link to a relevant article on AI ethics in code generation]&lt;/li&gt;
&lt;li&gt;&amp;quot;Fine-tuning Large Language Models for Code Generation&amp;quot; - (Example: Tutorial or blog post from Hugging Face or a machine learning community.), [Link to a relevant tutorial]&lt;/li&gt;
&lt;li&gt;PyTorch Official Website.), &lt;a href=&quot;https://pytorch.org/&quot;&gt;https://pytorch.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;How Generative AI is Changing Software Development&amp;quot; - (Example: Article from a major tech news outlet or analyst firm like Gartner.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Practical Applications of AI in Coding&amp;quot; - (Example: Blog post showcasing real-world use cases.), [Link to a relevant blog post]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Artificial Intelligence</category><category>Machine Learning</category><category>Software Engineering</category><category>Code Generation</category><category>Python</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0058-building-a-code-generative-ai-model-empowering-code-writing-with-ai/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Understanding Generative AI in Depth</title><link>https://mkabumattar.com/blog/post/understanding-generative-ai-in-depth/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/understanding-generative-ai-in-depth/</guid><description>Discover the captivating realm of Generative AI in this comprehensive guide designed for seasoned software engineers. Delve into the nuances of Generative AI, differentiate it from conventional AI and machine learning, explore practical use cases, and find answers to frequently asked questions.</description><pubDate>Fri, 25 Aug 2023 00:04:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the ever-evolving landscape of artificial intelligence, it&amp;#39;s paramount for senior software engineers to remain at the forefront of emerging technologies. One such technology that has garnered significant attention in recent years is Generative AI, often affectionately abbreviated as GenAI. But what precisely is Generative AI, and how does it diverge from traditional AI and Machine Learning (ML)? In this comprehensive guide, we will embark on a journey to explore the core concepts of Generative AI, delve into real-world instances, and address some of the pressing questions that often arise. So, let&amp;#39;s embark on this expedition!&lt;/p&gt;
&lt;h2&gt;What is Generative AI?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Generative AI&lt;/strong&gt;, or GenAI in concise terms, represents a subfield within artificial intelligence dedicated to empowering machines with the capacity to autonomously generate content. This content can manifest in diverse forms, encompassing textual narratives, vivid images, harmonious melodies, and even dynamic videos. Unlike traditional AI systems that are meticulously crafted for specific tasks, heavily reliant on predefined rules and datasets, Generative AI showcases a remarkable aptitude for crafting novel and original content devoid of explicit programming.&lt;/p&gt;
&lt;h3&gt;How Does Generative AI Operate?&lt;/h3&gt;
&lt;p&gt;At the heart of Generative AI lie &lt;strong&gt;neural networks&lt;/strong&gt;, particularly the &lt;strong&gt;Generative Adversarial Networks (GANs)&lt;/strong&gt; and &lt;strong&gt;Recurrent Neural Networks (RNNs)&lt;/strong&gt;. GANs, an acronym that encapsulates their dual nature, consist of two neural networks: a &lt;strong&gt;generator&lt;/strong&gt; and a &lt;strong&gt;discriminator&lt;/strong&gt;. These two entities work in tandem - the generator crafts content, while the discriminator critically evaluates it. This adversarial synergy propels the generator to consistently enhance its output until it attains a level of indistinguishability from content conceived by humans.&lt;/p&gt;
&lt;p&gt;Conversely, RNNs specialize in generating sequences of data, a domain where they excel - be it generating text, music, or other sequential formats. They employ feedback loops to meticulously process and generate data step by step, thereby enabling the creation of coherent and contextually aware content.&lt;/p&gt;
&lt;p&gt;In essence, Generative AI imbibes knowledge from the data it ingests and orchestrates content by prognosticating what should ensue based on the discerned patterns. It&amp;#39;s a captivating exemplification of how AI systems can replicate human creativity and inventiveness.&lt;/p&gt;
&lt;h3&gt;What Are Some Examples of Generative AI?&lt;/h3&gt;
&lt;p&gt;Generative AI has insinuated itself into various domains, sowing seeds of innovation across diverse industries. Here are some striking examples:&lt;/p&gt;
&lt;h4&gt;1. &lt;strong&gt;Text Generation&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Generative AI models like OpenAI&amp;#39;s GPT-3 have illuminated their prowess in generating text with a human-like quality. These models can craft essays, respond to inquiries, and even concoct code snippets - a boon for content creation and natural language comprehension.&lt;/p&gt;
&lt;h4&gt;2. &lt;strong&gt;Image Synthesis&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;GANs have been harnessed to concoct hyper-realistic images, some of which are so impeccable that they defy differentiation from photographs captured by humans. This innovation finds applications in graphic design, art, and the burgeoning landscape of fashion.&lt;/p&gt;
&lt;h4&gt;3. &lt;strong&gt;Music Composition&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Generative AI has ventured into the realm of musical composition, crafting melodious pieces spanning classical opuses to contemporary symphonies. Composers and musicians leverage AI-generated compositions as founts of inspiration or incorporate them seamlessly into their creative oeuvres.&lt;/p&gt;
&lt;h4&gt;4. &lt;strong&gt;Video Generation&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;AI-powered systems have ventured into the creation of video content by meticulously generating individual frames and seamlessly stitching them together. This groundbreaking development is revolutionizing the animation and video production industries by automating the laborious and time-consuming aspects of content creation.&lt;/p&gt;
&lt;h2&gt;What Sets Generative AI Apart from Traditional AI?&lt;/h2&gt;
&lt;p&gt;Having grasped the fundamentals of Generative AI, let&amp;#39;s embark on an expedition to understand how it distinguishes itself from traditional AI systems.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;1. Creativity and Autonomy&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Traditional AI systems are regimented by rule-based paradigms, operating within predefined confines. They execute tasks in accordance with pre-programmed instructions and structured data. Conversely, Generative AI radiates with creativity and autonomy, conjuring content without the crutch of explicit programming. It has the uncanny ability to manifest entirely novel, unscripted outputs, rendering it exceptionally adaptable across multifarious applications.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;2. Data-Driven Learning&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Generative AI is predicated upon substantial datasets for its learning and content generation prowess. It thrives sans meticulously crafted rules or substantial human intervention. Traditional AI, on the other hand, frequently leans upon manually contrived algorithms and constricted datasets, a characteristic that renders it less versatile by comparison.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;3. Versatility&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Generative AI epitomizes versatility, proficiently wielding its powers to generate a kaleidoscope of content types - from text to images, music, and beyond. Traditional AI systems, contrastingly, are typically tailored for specific tasks, shackled by limited flexibility when transitioning between divergent responsibilities.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;4. Potential for Creative Collaboration&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Generative AI extends an olive branch as a creative collaborator, extending a helping hand to professionals across various fields by generating content ripe for further refinement or customization. Traditional AI, conversely, serves as a tool primarily employed for automation and optimization, rather than actively participating in creative collaborations.&lt;/p&gt;
&lt;h2&gt;Generative AI vs. Machine Learning: What&amp;#39;s the Difference?&lt;/h2&gt;
&lt;p&gt;Having established the distinctions between Generative AI and traditional AI, let&amp;#39;s pivot our focus towards disentangling Generative AI from the broader scope of Machine Learning (ML).&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;1. Scope and Focus&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Machine Learning casts a wider net, encompassing a diverse array of techniques dedicated to instructing machines in the art of learning from data and subsequently making predictions or decisions. Generative AI, in contrast, constitutes a specific subset of ML, its chief preoccupation revolving around the act of generating content.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;2. Goal and Output&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;ML centers its aspirations on nurturing models capable of delivering predictions or classifications grounded in input data. Generative AI, as its nomenclature implies, directs its energies towards the act of spawning new data, be it text, images, or other manifestations of content.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;3. Training Paradigms&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In the realm of ML, models are honed and polished via techniques like supervised learning, unsupervised learning, or reinforcement learning. Generative AI, on the other hand, leans heavily upon methodologies such as GANs and RNNs for content generation, ushering in a distinctive training paradigm when juxtaposed with traditional ML models.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;4. Use Cases&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;ML adorns myriad domains, extending its influence to predictive analytics, recommendation systems, and natural language processing, among others. Generative AI, though similarly versatile, excels when tasked with content creation and generation, carving its niche in a distinct set of applications.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions (FAQ) About Generative AI&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s address some common inquiries that tend to surface when the topic of Generative AI comes to the fore:&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Q1: Is Generative AI the same as Q&amp;amp;A AI, such as chatbots?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;No, Generative AI and Q&amp;amp;A AI are distinguishable entities. Q&amp;amp;A AI, often embodied by chatbots and virtual assistants, is tailored for the explicit purpose of responding to questions grounded in pre-existing knowledge or data. Generative AI, conversely, ventures into uncharted territory, crafting content from the ground up, sans reliance on pre-existing knowledge.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Q2: Can Generative AI supplant human creativity?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Generative AI undoubtedly wields the power to conjure creative content, but it is best perceived as a tool poised to augment human creativity rather than usurp it. It serves as a wellspring of inspiration for artists, writers, and designers, generating ideas and content that humans can subsequently refine and curate.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Q3: Is Generative AI the exclusive purview of large organizations armed with extensive datasets?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While access to copious datasets can undoubtedly bolster the capabilities of Generative AI, there exist pre-trained models amenable to fine-tuning for specific tasks, even in scenarios where datasets are more modest in scale. This accessibility democratizes Generative AI, rendering it applicable across a broad spectrum of organizations and developers.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Q4: What ethical considerations are intertwined with Generative AI?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Generative AI unfurls a tapestry of ethical considerations, particularly in the realm of generating counterfeit content, deepfakes, and the specter of misuse. Mitigating these risks necessitates the implementation of responsible AI practices, including vigilant content moderation and a commitment to transparency.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Q5: How can I embark on my journey into Generative AI development?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To embark on the voyage of Generative AI development, you must lay a robust foundation in the realms of machine learning and deep learning. Familiarize yourself with the intricate landscapes of frameworks such as TensorFlow and PyTorch, and venture forth into the realm of pre-trained models and tutorials readily available in the digital realm. Remember, experimentation and a commitment to perpetual learning serve as your compass in this expansive landscape.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Generative AI stands as a groundbreaking edifice within the realm of artificial intelligence. Its ability to autonomously birth content carries the promise of reshaping numerous industries, from content creation to the realms of entertainment and beyond. As seasoned software engineers, grasping the nuances of Generative AI could well serve as the key to unlocking new vistas of innovation within your projects, propelling you to the vanguard of technological progress.&lt;/p&gt;
&lt;p&gt;In this compendious guide, we embarked on a voyage to unravel the essence of Generative AI, explored its real-world applications, and illuminated the distinctions setting it apart from traditional AI and Machine Learning. Our aspiration is that this journey has served to demystify Generative AI, igniting your curiosity and prompting further exploration of its boundless possibilities.&lt;/p&gt;
&lt;p&gt;Bear in mind that the domain of AI is a perpetually shifting landscape. By embracing Generative AI today, you might just set in motion the groundbreaking developments that shall define your projects of tomorrow.&lt;/p&gt;
&lt;p&gt;Do you have more queries or insights to share regarding Generative AI? Feel free to share your thoughts and questions in the comments section below!&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Goodfellow, I., Pouget-Abadie, J., Mirza, M., Xu, B., Warde-Farley, D., Ozair, S., ... &amp;amp; Bengio, Y. (2014). Generative adversarial nets. In &lt;em&gt;Advances in neural information processing systems&lt;/em&gt; (pp. 2672-2680.), &lt;a href=&quot;https://papers.nips.cc/paper/2014/file/5ca3e9b122f61f8f06494c97b1afccf3-Paper.pdf&quot;&gt;https://papers.nips.cc/paper/2014/file/5ca3e9b122f61f8f06494c97b1afccf3-Paper.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;What is Generative AI?&amp;quot; - NVIDIA Blogs.), &lt;a href=&quot;https://blogs.nvidia.com/blog/2023/08/14/what-is-generative-ai/&quot;&gt;https://blogs.nvidia.com/blog/2023/08/14/what-is-generative-ai/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Generative AI: A Creative New World&amp;quot; - McKinsey &amp;amp; Company.), &lt;a href=&quot;https://www.mckinsey.com/featured-insights/mckinsey-explainers/what-is-generative-ai&quot;&gt;https://www.mckinsey.com/featured-insights/mckinsey-explainers/what-is-generative-ai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenAI GPT-3.), &lt;a href=&quot;https://openai.com/gpt-3/&quot;&gt;https://openai.com/gpt-3/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Recurrent Neural Networks (RNNs) Explained&amp;quot; - Towards Data Science.), &lt;a href=&quot;https://towardsdatascience.com/understanding-recurrent-neural-networks-rnn-and-long-short-term-memory-lstm-6496002156AF&quot;&gt;https://towardsdatascience.com/understanding-recurrent-neural-networks-rnn-and-long-short-term-memory-lstm-6496002156AF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;The Illustrated Transformer&amp;quot; by Jay Alammar. (Explains the architecture behind many modern GenAI models.), &lt;a href=&quot;http://jalammar.github.io/illustrated-transformer/&quot;&gt;http://jalammar.github.io/illustrated-transformer/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Ethical Considerations for Generative AI&amp;quot; - Stanford HAI.), &lt;a href=&quot;https://hai.stanford.edu/news/generative-ai-raises-host-ethical-concerns&quot;&gt;https://hai.stanford.edu/news/generative-ai-raises-host-ethical-concerns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;TensorFlow Official Website.), &lt;a href=&quot;https://www.tensorflow.org/&quot;&gt;https://www.tensorflow.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PyTorch Official Website.), &lt;a href=&quot;https://pytorch.org/&quot;&gt;https://pytorch.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Generative AI for Dummies&amp;quot; - (Example: A beginner-friendly guide from a reputable source like IBM or Google Cloud.), [Link to a relevant guide]&lt;/li&gt;
&lt;li&gt;&amp;quot;Deep Learning&amp;quot; by Ian Goodfellow, Yoshua Bengio, and Aaron Courville. MIT Press, 2016. (Comprehensive textbook.), &lt;a href=&quot;https://www.deeplearningbook.org/&quot;&gt;https://www.deeplearningbook.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;The State of AI in 2023: Generative AI’s Breakout Year&amp;quot; - McKinsey &amp;amp; Company.), &lt;a href=&quot;https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai-in-2023-generative-ais-breakout-year&quot;&gt;https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai-in-2023-generative-ais-breakout-year&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;What are Large Language Models (LLMs)?&amp;quot; - AWS.), &lt;a href=&quot;https://aws.amazon.com/what-is/large-language-models/&quot;&gt;https://aws.amazon.com/what-is/large-language-models/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Artificial Intelligence</category><category>Generative AI</category><category>Machine Learning</category><category>Deep Learning</category><category>Software Engineering</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0057-understanding-generative-ai-in-depth/hero.jpg" length="0" type="image/jpeg"/></item><item><title>The ORM Dilemma: To Use or Not to Use</title><link>https://mkabumattar.com/blog/post/why-not-to-use-orm-in-nodejs/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/why-not-to-use-orm-in-nodejs/</guid><description>Explore the intricacies of utilizing Object-Relational Mapping (ORM) in Node.js, TypeScript, and Express. Seasoned software engineers dissect the pros and cons, offering invaluable insights into when and why you should consider alternatives to ORM for your database operations.</description><pubDate>Thu, 24 Aug 2023 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the world of software engineering, seasoned professionals are often confronted with pivotal decisions that wield substantial influence over the course and outcome of a project. Among these choices is the perennial dilemma of whether to employ an Object-Relational Mapping (ORM) tool for handling database interactions. Should you eschew an ORM entirely? Or should you harness the convenience it offers when working with technologies like Node.js and TypeScript, particularly in conjunction with Express? This article endeavors to dissect the pros and cons of employing an ORM and provide insights into scenarios where alternatives might be a more judicious choice.&lt;/p&gt;
&lt;h2&gt;A Glimpse into ORM&lt;/h2&gt;
&lt;p&gt;Before we plunge into the nuanced discourse of whether or not to utilize ORM, let&amp;#39;s briefly acquaint ourselves with what ORM entails and the functions it serves. At its core, an Object-Relational Mapping tool is a software framework that streamlines communication between an application and a relational database. It adroitly abstracts the intricacies of database interactions, enabling developers to interact with database entities as if they were conventional objects in their chosen programming language.&lt;/p&gt;
&lt;h3&gt;The Advantages of ORM&lt;/h3&gt;
&lt;p&gt;ORM proffers several compelling advantages that render it an alluring choice for developers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Complexity Abstraction&lt;/strong&gt;: One of ORM&amp;#39;s prime virtues lies in its ability to shield developers from the labyrinthine depths of SQL and the idiosyncrasies of database-specific operations. This abstraction proves invaluable, particularly when handling intricate queries.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Seamless Language Integration&lt;/strong&gt;: ORM seamlessly dovetails with the programming language being employed. This harmonious integration permits developers to manipulate database records using native language constructs, culminating in code that is not only more maintainable but also notably more readable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-Database Compatibility&lt;/strong&gt;: A plethora of ORM libraries offer robust support for multiple database systems, making the task of transitioning from one database to another a relatively painless endeavor. This flexibility can prove invaluable in evolving projects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expedited Development&lt;/strong&gt;: ORM expedites the development process by alleviating the burden of crafting boilerplate code for routine database operations such as Create, Read, Update, and Delete (CRUD) actions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While the advantages of ORM are compelling, we must now pivot our attention to the flip side and meticulously examine the disadvantages.&lt;/p&gt;
&lt;h2&gt;The Disadvantages of ORM&lt;/h2&gt;
&lt;p&gt;Undoubtedly, ORM is a potent tool, but it does not traverse the software landscape unburdened. Here are the principal disadvantages that warrant careful consideration:&lt;/p&gt;
&lt;h3&gt;1. Performance Overheads&lt;/h3&gt;
&lt;p&gt;Introducing ORM into the mix invariably adds an abstraction layer between your application and the database. While this abstraction might be conducive to code readability and maintainability, it often exacts a performance toll. The SQL queries generated by ORM may not always be as optimized as handcrafted SQL, particularly when grappling with intricate queries or high-throughput scenarios.&lt;/p&gt;
&lt;h3&gt;2. The Learning Curve&lt;/h3&gt;
&lt;p&gt;The adoption of an ORM tool often entails navigating a learning curve. Developers must acquaint themselves with the intricacies of the ORM&amp;#39;s Application Programming Interface (API), a process that can consume valuable time. Additionally, comprehending how the ORM translates high-level operations into SQL queries becomes paramount when striving to optimize performance.&lt;/p&gt;
&lt;h3&gt;3. Limited Control&lt;/h3&gt;
&lt;p&gt;ORM&amp;#39;s modus operandi involves abstracting database operations, which inherently implies a degree of control relinquishment over the SQL queries it generates. In scenarios necessitating fine-grained control over queries for performance optimization, the rigid structure of ORM might prove restrictive.&lt;/p&gt;
&lt;h3&gt;4. Code Bloat&lt;/h3&gt;
&lt;p&gt;While ORM effectively trims the fat of boilerplate code in common scenarios, it can paradoxically lead to code bloat in more complex situations. Achieving fine-grained control over database interactions often mandates the crafting of custom code within the confines of the ORM framework, a practice that can be verbose and challenging to maintain.&lt;/p&gt;
&lt;h2&gt;The Necessity of ORM: A Delicate Balance&lt;/h2&gt;
&lt;p&gt;Having scrutinized both the advantages and disadvantages of ORM, a pertinent question lingers: Is an ORM an indispensable tool? The resounding answer is, &amp;quot;It depends.&amp;quot;&lt;/p&gt;
&lt;h3&gt;When to Contemplate the Adoption of ORM&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rapid Prototyping&lt;/strong&gt;: If your project&amp;#39;s primary objective revolves around expeditiously materializing a minimum viable product (MVP), an ORM can serve as an invaluable ally. It liberates you from the quagmire of SQL queries, allowing you to channel your energies into molding the logic of your application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Team Expertise&lt;/strong&gt;: If your development ensemble boasts greater proficiency in the programming language of your choice as opposed to SQL, then opting for ORM is a judicious course of action. It empowers your team to function efficaciously, culminating in the delivery of high-quality code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-Database Compatibility&lt;/strong&gt;: Should your project necessitate support for multiple database systems, an ORM shines as a pragmatic choice. It transcends the discrepancies that segregate databases, rendering transitions from one database to another a relatively seamless endeavor.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;When to Exercise Caution with ORM&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exacting Performance Demands&lt;/strong&gt;: In scenarios where your application is subjected to stringent performance prerequisites, particularly when grappling with intricate queries or high transaction rates, the deployment of raw SQL or a database-specific library might be the wiser selection. This affords you the latitude to fine-tune SQL queries for optimal performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database-Specific Features&lt;/strong&gt;: Projects that heavily rely on database-specific features or the execution of advanced SQL operations that elude the grasp of ORM might discover greater efficiency in resorting to native SQL.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requisite Query Control&lt;/strong&gt;: Should the exigencies of your project necessitate granular control over the SQL queries executed by your application, the use of ORM may impose unwarranted limitations. In such instances, the composition of custom SQL queries emerges as the more judicious course of action.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Pragmatic Alternatives to ORM&lt;/h2&gt;
&lt;p&gt;For scenarios where the adoption of ORM might not align seamlessly with your project&amp;#39;s requisites, it becomes imperative to explore pragmatic alternatives. Below, we outline a couple of alternatives worthy of contemplation.&lt;/p&gt;
&lt;h3&gt;1. Query Builders&lt;/h3&gt;
&lt;p&gt;Query builders, exemplified by libraries such as Knex.js, proffer a middle-ground solution. They empower you to programmatically construct SQL queries using JavaScript, striking a harmonious balance between raw SQL and the abstraction provided by ORM. Query builders become especially invaluable when the need for query control converges with the desire for code that remains readable.&lt;/p&gt;
&lt;p&gt;Consider a TypeScript and PostgreSQL example using Knex.js:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import * as Knex from &amp;#39;knex&amp;#39;;

const knex = Knex({
  client: &amp;#39;pg&amp;#39;,
  connection: {
    host: &amp;#39;your-database-host&amp;#39;,
    user: &amp;#39;your-username&amp;#39;,
    password: &amp;#39;your-password&amp;#39;,
    database: &amp;#39;your-database-name&amp;#39;,
  },
});

async function getUsers() {
  return await knex.select(&amp;#39;*&amp;#39;).from(&amp;#39;users&amp;#39;);
}

async function addUser(user: any) {
  return await knex(&amp;#39;users&amp;#39;).insert(user);
}

async function getComplexData(
  country: string,
  orderDate: Date,
  category: string,
) {
  // Define Common Table Expressions (CTEs)
  const usersFromCountry = knex(&amp;#39;users&amp;#39;).where(&amp;#39;country&amp;#39;, country);
  const ordersFromLast30Days = knex(&amp;#39;orders&amp;#39;).where(
    &amp;#39;order_date&amp;#39;,
    &amp;#39;&amp;gt;=&amp;#39;,
    orderDate,
  );
  const booksOrderItems = knex(&amp;#39;order_items&amp;#39;)
    .join(&amp;#39;products&amp;#39;, &amp;#39;order_items.product_id&amp;#39;, &amp;#39;=&amp;#39;, &amp;#39;products.id&amp;#39;)
    .where(&amp;#39;products.category&amp;#39;, category);

  // Build the main query using CTEs
  const query = knex
    .with(&amp;#39;users_from_country&amp;#39;, usersFromCountry)
    .with(&amp;#39;orders_from_last_30_days&amp;#39;, ordersFromLast30Days)
    .with(&amp;#39;books_order_items&amp;#39;, booksOrderItems)
    .select(
      &amp;#39;users_from_country.name&amp;#39;,
      &amp;#39;orders_from_last_30_days.order_date&amp;#39;,
      &amp;#39;books_order_items.product_name&amp;#39;,
    )
    .from(&amp;#39;users_from_country&amp;#39;)
    .leftJoin(
      &amp;#39;orders_from_last_30_days&amp;#39;,
      &amp;#39;users_from_country.id&amp;#39;,
      &amp;#39;orders_from_last_30_days.user_id&amp;#39;,
    )
    .leftJoin(
      &amp;#39;books_order_items&amp;#39;,
      &amp;#39;orders_from_last_30_days.id&amp;#39;,
      &amp;#39;books_order_items.order_id&amp;#39;,
    );

  return query;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Raw SQL&lt;/h3&gt;
&lt;p&gt;In cases where optimal performance is paramount, and you yearn for absolute control over your queries, the embrace of raw SQL queries emerges as the superior choice. While this path demands a heightened level of diligence to fend off the specter of SQL injection, it confers an unparalleled degree of control and efficiency.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of TypeScript code executing a raw SQL query with the &lt;code&gt;pg&lt;/code&gt; library for PostgreSQL:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import {Pool} from &amp;#39;pg&amp;#39;;

const pool = new Pool({
  user: &amp;#39;your-username&amp;#39;,
  host: &amp;#39;your-database-host&amp;#39;,
  database: &amp;#39;your-database-name&amp;#39;,
  password: &amp;#39;your-password&amp;#39;,
  port: 5432, // PostgreSQL default port
});

async function getUsers() {
  const client = await pool.connect();
  try {
    const result = await client.query(&amp;#39;SELECT * FROM users&amp;#39;);
    return result.rows;
  } finally {
    client.release();
  }
}

async function addUser(user: any) {
  const client = await pool.connect();
  try {
    const query = {
      text: &amp;#39;INSERT INTO users(name, email) VALUES($1, $2)&amp;#39;,
      values: [user.name, user.email],
    };
    await client.query(query);
  } finally {
    client.release();
  }
}

async function getComplexData(
  country: string,
  orderDate: Date,
  category: string,
) {
  const client = await pool.connect();

  try {
    // Define the SQL query with placeholders for parameters
    const sqlQuery = `
      WITH
        users_from_country AS (
          SELECT * FROM users WHERE country = $1
        ),
        orders_from_last_30_days AS (
          SELECT * FROM orders WHERE order_date &amp;gt;= $2
        ),
        books_order_items AS (
          SELECT * FROM order_items
          JOIN products ON order_items.product_id = products.id
          WHERE products.category = $3
        )

      SELECT
        users_from_country.name,
        orders_from_last_30_days.order_date,
        books_order_items.product_name
      FROM users_from_country
      LEFT JOIN orders_from_last_30_days
        ON users_from_country.id = orders_from_last_30_days.user_id
      LEFT JOIN books_order_items
        ON orders_from_last_30_days.id = books_order_items.order_id
    `;

    // Execute the SQL query with parameters
    const result = await client.query(sqlQuery, [country, orderDate, category]);
    return result.rows;
  } finally {
    client.release();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the realm of software engineering, complexity often begets simplicity. When confronted with the decision of whether to adopt ORM in the context of Node.js, TypeScript, and Express, it&amp;#39;s wise to consider a more streamlined approach. Instead of embracing ORM, consider these insights:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prioritize Performance&lt;/strong&gt;: For projects with demanding performance requirements, especially those involving intricate queries or high transaction volumes, opting for raw SQL or a database-specific library can lead to more efficient outcomes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Embrace Database Expertise&lt;/strong&gt;: If your team is well-versed in SQL and the intricacies of the chosen database, utilizing that expertise directly can lead to more optimized database interactions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintain Control&lt;/strong&gt;: When granular control over SQL queries is imperative, using ORM may limit your flexibility. Crafting custom SQL queries allows you to fine-tune operations for optimal performance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In essence, the decision not to use ORM can be a strategic one, particularly when project goals align with performance, database expertise, and query control. So, when navigating the ORM dilemma, consider a more direct route to achieve your project&amp;#39;s objectives.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&amp;quot;What is an ORM? How ORMs work and why you should use them&amp;quot; - Prisma.), &lt;a href=&quot;https://www.prisma.io/dataguide/types/relational/what-is-an-orm&quot;&gt;https://www.prisma.io/dataguide/types/relational/what-is-an-orm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;ORM vs. SQL: How to choose the right one for your project&amp;quot; - LogRocket Blog.), &lt;a href=&quot;https://blog.logrocket.com/orm-vs-sql-how-to-choose-the-right-one-for-your-project/&quot;&gt;https://blog.logrocket.com/orm-vs-sql-how-to-choose-the-right-one-for-your-project/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Knex.js - SQL query builder for JavaScript.), &lt;a href=&quot;https://knexjs.org/&quot;&gt;https://knexjs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;node-postgres (pg) - Non-blocking PostgreSQL client for Node.js.), &lt;a href=&quot;https://node-postgres.com/&quot;&gt;https://node-postgres.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Why I Don&amp;#39;t Use ORMs&amp;quot; - (Example: A popular developer blog post discussing the downsides of ORMs.), [Link to a well-known article, e.g., by a prominent developer or on a site like Hacker News discussion summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;The Vietnam of Computer Science&amp;quot; by Ted Neward (Discusses the ORM problem.), &lt;a href=&quot;http://blogs.tedneward.com/post/the-vietnam-of-computer-science/&quot;&gt;http://blogs.tedneward.com/post/the-vietnam-of-computer-science/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sequelize ORM Documentation (Popular Node.js ORM.), &lt;a href=&quot;https://sequelize.org/&quot;&gt;https://sequelize.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;TypeORM Documentation (Popular TypeScript ORM.), &lt;a href=&quot;https://typeorm.io/&quot;&gt;https://typeorm.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;When to Use an ORM (and When Not To)&amp;quot; - SitePoint.), &lt;a href=&quot;https://www.sitepoint.com/when-to-use-an-orm/&quot;&gt;https://www.sitepoint.com/when-to-use-an-orm/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;SQL vs. NoSQL: What&amp;#39;s the difference?&amp;quot; - IBM. (While not directly ORM, understanding database types helps in choosing data access strategies.), &lt;a href=&quot;https://www.ibm.com/cloud/blog/sql-vs-nosql&quot;&gt;https://www.ibm.com/cloud/blog/sql-vs-nosql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Understanding the Node.js Event Loop&amp;quot; - Node.js Documentation. (Relevant for understanding performance implications of database calls.), &lt;a href=&quot;https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/&quot;&gt;https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Database Performance for Developers&amp;quot; - (Example: A book or comprehensive guide on database performance.), [Link to a relevant book or guide, e.g., on O&amp;#39;Reilly or similar]&lt;/li&gt;
&lt;li&gt;&amp;quot;Pros and Cons of Using an ORM&amp;quot; - GeeksforGeeks.), &lt;a href=&quot;https://www.geeksforgeeks.org/pros-and-cons-of-using-an-orm/&quot;&gt;https://www.geeksforgeeks.org/pros-and-cons-of-using-an-orm/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Backend Development</category><category>Node.js</category><category>Database Management</category><category>Software Architecture</category><category>TypeScript</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0056-why-not-to-use-orm-in-nodejs/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Mastering Caching Strategies with Redis Cache: Boosting Performance in Node.js and TypeScript</title><link>https://mkabumattar.com/blog/post/mastering-caching-strategies-redis-nodejs-typescript/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/mastering-caching-strategies-redis-nodejs-typescript/</guid><description>Explore the world of caching in Redis and supercharge your Node.js and TypeScript applications with advanced caching strategies. Learn about Cache-Aside, Read-Through, Write-Through, and Write-Behind patterns, as well as the Redis cache key strategy. Discover the power of Redis caching for turbocharging your applications.</description><pubDate>Wed, 23 Aug 2023 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the ever-evolving realm of software development, the pursuit of optimizing application performance is a perpetual endeavor. Among the arsenal of strategies to attain this goal, the implementation of caching mechanisms stands as a powerful approach. Redis, a high-performing in-memory data store, reigns as a favored choice for caching within Node.js and TypeScript applications. In this comprehensive blog post, we embark on a journey into the intricate realm of caching with Redis. We will explore an array of caching strategies that have the potential to propel your application&amp;#39;s performance to new heights.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Section 1: Grasping Redis as a Caching Solution&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Before we plunge into the intricacies of caching strategies, let&amp;#39;s take a moment to fathom why Redis emerges as a stellar choice for caching in Node.js and TypeScript applications. Redis, an open-source in-memory data store, stands renowned for its blistering fast read and write operations. Crafted to handle colossal datasets with minimal latency, Redis presents itself as the ideal candidate for caching frequently accessed data.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Section 2: Unveiling the Redis Cache Key Strategy&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;An indispensable facet of harnessing Redis&amp;#39;s full potential for caching lies in crafting a robust cache key strategy. The cache key serves as the beacon guiding the retrieval of cached data. It is imperative to forge a key strategy that marries uniqueness with meaningfulness.&lt;/p&gt;
&lt;p&gt;Within Redis, keys serve as the gateways to rapid data storage and retrieval. A meticulously constructed cache key strategy wields the power to significantly impact the performance and efficiency of your caching system. Typically, cache keys amalgamate multiple elements, including a namespace, the cached object or data, and any pertinent identifiers. This meticulous approach ensures the keys&amp;#39; uniqueness, mitigates collisions, and paves the way for effortless data retrieval.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Section 3: A Survey of the Various Caching Types in Redis&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Redis extends its support to a spectrum of caching patterns, each tailored to cater to specific use cases. Let&amp;#39;s embark on a journey through some of the most commonly embraced types:&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Cache-Aside Pattern&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The Cache-Aside pattern, sometimes referred to as Lazy-Loading or Read-Through caching, stands as the simplest caching strategy. Under this pattern, your application code shoulders the responsibility of verifying the cache prior to accessing data from the primary data store, such as a database. If the cache lacks the requisite data, it is procured from the data store and subsequently stashed within the cache for future utilization. This approach, though straightforward, necessitates judicious handling of cache invalidation.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Read-Through Pattern&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;An evolutionary extension of the Cache-Aside pattern, the Read-Through pattern introduces an abstraction layer between your application and the cache. When your application solicits data, this intermediary layer conducts a preliminary cache check. In the absence of the data within the cache, it retrieves the data from the data store, populates the cache, and subsequently furnishes the data to your application. This methodology streamlines your application code by abstracting cache access.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Write-Through Pattern&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In the Write-Through pattern, data undergoes simultaneous storage in both the cache and the primary data store. When your application initiates write or data update operations, the cache is the initial recipient of the data. Subsequently, the data is synchronized with the data store. While this approach introduces a modicum of overhead to write operations, it ensconces the cache with the most up-to-date data at all times.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Write-Behind Pattern&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The Write-Behind pattern, also recognized as Write-Behind Caching or Write-Behind Processing, ventures down an alternative route. Within this framework, write operations first transpire within the cache, followed by an asynchronous relay to the primary data store. This approach serves to heighten write performance by mitigating immediate write latency. However, it necessitates vigilant management to preserve data consistency.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Section 4: Navigating the Realm of Popular Caching Strategies&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Having embarked on an expedition through the diverse caching patterns, it is imperative to comprehend the contexts in which each strategy radiates.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Cache-Aside Pattern: Simplicity Meets Control&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The Cache-Aside pattern proves its mettle when simplicity and meticulous control over cached data are paramount. This approach empowers you to make judicious decisions regarding when to populate the cache, offering direct control over cache invalidation. Nevertheless, it demands judicious programming to ensure data consistency between the cache and the primary data store.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Read-Through Pattern: Abstracting Cache Interaction&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The Read-Through pattern steps into the limelight when the goal is to abstract cache interaction from your application&amp;#39;s codebase. By offloading cache management to an abstraction layer, this pattern simplifies your codebase. It finds its niche in applications laden with intricate data access logic, where centralizing caching decisions proves advantageous.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Write-Through Pattern: Upholding Data Consistency&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In scenarios where data consistency takes precedence and you are amenable to bearing a marginal overhead in write operations, the Write-Through pattern emerges as the stalwart choice. It guarantees that the cache perpetually houses up-to-the-minute data, rendering it a fitting choice for applications where stale data could prove detrimental.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Write-Behind Pattern: Pinnacle of Write Performance&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The Write-Behind pattern shines when the objective is to optimize write performance while permitting a degree of eventual consistency. Through asynchronous data relay to the primary data store, it circumvents immediate write latency, a boon in applications replete with high write loads.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Section 5: Breathing Life into Caching in Node.js and TypeScript with Redis&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;With a firm grasp of caching strategies, it&amp;#39;s time to venture into the realm of implementation within Node.js and TypeScript using Redis.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Initiating Redis in Node.js&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To commence this journey, you must equip yourself with the Redis client library tailored for Node.js. The &lt;code&gt;ioredis&lt;/code&gt; library, available in both Promise-based and callback-based variants, stands as a favored choice. Installation is effortlessly accomplished through npm or yarn:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;npm install ioredis
# or
yarn add ioredis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the library in place, you gain the capability to establish a connection with your Redis instance, setting the stage for caching.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Embarking on Cache-Aside in Node.js&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To breathe life into Cache-Aside within Node.js, your code must be poised to conduct cache checks prior to data store access. The following snippet, employing the &lt;code&gt;ioredis&lt;/code&gt; library, provides a streamlined example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import Redis from &amp;#39;ioredis&amp;#39;;

// Instantiate a Redis client
const redis = new Redis();

// Define a function to retrieve data from either the cache or the data store
async function getDataFromCacheOrStore(key: string) {
  // Check the cache for the desired data
  const cachedData = await redis.get(key);

  // If the cache yields the data, return it
  if (cachedData) {
    return cachedData;
  }

  // Otherwise, retrieve the data from the data store
  const dataFromStore = await fetchDataFromStore(key);

  // Populate the cache with the data for future use
  await redis.set(key, JSON.stringify(dataFromStore));

  // Return the data
  return dataFromStore;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code employs an initial cache check for the requested data. In the absence of the data within the cache, it forages from the data store,&lt;/p&gt;
&lt;p&gt;deposits it within the cache, and eventually delivers it.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Embarking on Read-Through in Node.js&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To embrace the Read-Through pattern within Node.js, you must erect an abstraction layer responsible for managing both cache and data store interactions. The ensuing code illustrates this concept:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import Redis from &amp;#39;ioredis&amp;#39;;

// Instantiate a Redis client
const redis = new Redis();

// Define a function to retrieve data, abstracting cache and data store interactions
async function getData(key: string) {
  // Fetch data from the cache
  const cachedData = await redis.get(key);

  // Furnish the data if found within the cache
  if (cachedData) {
    return JSON.parse(cachedData);
  }

  // Retrieve the data from the data store
  const dataFromStore = await fetchDataFromStore(key);

  // Populate the cache with the fetched data
  await redis.set(key, JSON.stringify(dataFromStore));

  // Return the data
  return dataFromStore;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this code, the &lt;code&gt;getData&lt;/code&gt; function assumes the role of an intermediary, shielding your application code from the intricacies of cache and data store access.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Embarking on Write-Through in Node.js&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To set the wheels in motion for the Write-Through pattern within Node.js, it becomes imperative to adapt your write operations to encompass both cache and data store updates. The following code snippet elucidates this process:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import Redis from &amp;#39;ioredis&amp;#39;;

// Instantiate a Redis client
const redis = new Redis();

// Define a function to update data, ensuring synchronization between cache and data store
async function updateData(key: string, newData: Record&amp;lt;string, unknown&amp;gt;) {
  // Prioritize cache update
  await redis.set(key, JSON.stringify(newData));

  // Subsequently, update the data store
  await updateDataStore(key, newData);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this code, the &lt;code&gt;updateData&lt;/code&gt; function orchestrates atomic updates within the cache and data store, preserving data consistency.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Embarking on Write-Behind in Node.js&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The Write-Behind pattern within Node.js introduces intricacies due to its asynchronous data store writes. The ensuing code fragment offers an insight into its implementation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import Redis from &amp;#39;ioredis&amp;#39;;

// Instantiate a Redis client
const redis = new Redis();

// Define a function to update data, prioritizing cache updates and deferring data store updates asynchronously
async function updateData(key: string, newData: Record&amp;lt;string, unknown&amp;gt;) {
  // Initiate cache update
  await redis.set(key, JSON.stringify(newData));

  // Confer data store update asynchronously without awaiting its completion
  updateDataStore(key, newData);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within this code, the &lt;code&gt;updateData&lt;/code&gt; function instantiates an immediate cache update, followed by the asynchronous relay of data to the primary data store. This asynchronous facet endeavors to augment write performance, particularly in scenarios where immediate data store writes assume a less critical role.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Section 6: Harnessing Advanced Redis Features for Caching&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Redis encompasses advanced features that hold the potential to elevate your caching strategies to greater heights. Among these features are:&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Expiration Policies&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Redis extends the capability to set expiration times for keys. This feature proves invaluable when the goal is to safeguard cached data against staleness. By configuring an appropriate expiration time, you can automate the removal of outdated data from the cache.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Pub/Sub Messaging&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Redis boasts support for Publish/Subscribe (Pub/Sub) messaging, a feature that can be harnessed to broadcast notifications to multiple components within your application when data undergoes alterations. This capability becomes a potent asset in scenarios necessitating real-time updates.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Lua Scripting&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Redis grants the privilege of executing Lua scripts directly on the server. This feature serves as a formidable tool for the implementation of intricate caching logic, atomic updates across multiple keys, and other advanced functionalities.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Section 7: Scaling Redis for Caching in Expansive Applications&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;As your application undergoes expansion, the need to scale your Redis caching infrastructure becomes evident. Redis provides support for clustering and sharding, mechanisms that facilitate the dispersion of data across multiple Redis instances. This approach ensures not only high availability but also heightened performance, serving as a robust solution for your caching needs.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Section 8: Is Redis an Apt Choice for Caching?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;A frequently posed question centers on the suitability of Redis as a caching solution. In the majority of cases, Redis emerges as an exemplary choice, thanks to its exceptional performance, adaptability, and the gamut of caching patterns it accommodates. Nevertheless, it is imperative to meticulously weigh your specific use case and prerequisites. In scenarios characterized by exorbitant read and write loads, fine-tuning your Redis configuration may become a necessity, and exploration of alternative caching solutions may merit consideration.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Section 9: Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In conclusion, the mastery of caching strategies within the realm of Redis can wield a profound impact on the performance of your Node.js and TypeScript applications. By acquainting yourself with the Cache-Aside, Read-Through, Write-Through, and Write-Behind patterns, and by instating a robust Redis cache key strategy, you stand poised to unleash the full potential of Redis as a caching powerhouse. Whether you are crafting a diminutive web application or steering the helm of a sprawling, enterprise-scale system, Redis assumes the mantle of an invaluable tool for optimizing data access and elevating user experiences.&lt;/p&gt;
&lt;p&gt;Redis, with its innate simplicity, blazing speed, and a treasure trove of advanced features, stakes its claim as a premier choice for caching within the modern landscape of application development. So, without further ado, embark on this journey, experiment with caching patterns within your Node.js and TypeScript projects, and unleash the prowess of Redis to supercharge your applications.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Redis Official Website.), &lt;a href=&quot;https://redis.io/&quot;&gt;https://redis.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis Documentation - Caching.), &lt;a href=&quot;https://redis.io/docs/manual/cache/&quot;&gt;https://redis.io/docs/manual/cache/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ioredis&lt;/code&gt; - A robust, performance-focused and full-featured Redis client for Node.js.), &lt;a href=&quot;https://github.com/luin/ioredis&quot;&gt;https://github.com/luin/ioredis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Caching Strategies and How to Choose the Right One - AWS.), &lt;a href=&quot;https://aws.amazon.com/caching/caching-strategies/&quot;&gt;https://aws.amazon.com/caching/caching-strategies/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cache-Aside Pattern - Microsoft Azure Documentation.), &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/architecture/patterns/cache-aside&quot;&gt;https://learn.microsoft.com/en-us/azure/architecture/patterns/cache-aside&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching - Hazelcast Documentation.), &lt;a href=&quot;https://docs.hazelcast.com/hazelcast/latest/data-structures/map-persistence#read-through-write-through-write-behind-and-refresh-ahead-caching&quot;&gt;https://docs.hazelcast.com/hazelcast/latest/data-structures/map-persistence#read-through-write-through-write-behind-and-refresh-ahead-caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Designing Data-Intensive Applications&amp;quot; by Martin Kleppmann. (Chapter on Caching.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Redis Caching with Node.js: A Step-by-Step Guide&amp;quot; - LogRocket Blog.), &lt;a href=&quot;https://blog.logrocket.com/redis-caching-node-js/&quot;&gt;https://blog.logrocket.com/redis-caching-node-js/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis Best Practices - Redis Labs (now Redis.), &lt;a href=&quot;https://redis.com/ebook/appendix-a/a-3-installing-on-windows/a-3-2-best-practices/&quot;&gt;https://redis.com/ebook/appendix-a/a-3-installing-on-windows/a-3-2-best-practices/&lt;/a&gt; (Note: Look for general best practices, not just Windows-specific)&lt;/li&gt;
&lt;li&gt;&amp;quot;An Introduction to Caching in Node.js with Redis&amp;quot; - SitePoint.), &lt;a href=&quot;https://www.sitepoint.com/caching-node-js-redis/&quot;&gt;https://www.sitepoint.com/caching-node-js-redis/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis Pub/Sub Documentation.), &lt;a href=&quot;https://redis.io/docs/manual/pubsub/&quot;&gt;https://redis.io/docs/manual/pubsub/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis Lua Scripting Documentation.), &lt;a href=&quot;https://redis.io/docs/manual/programmability/lua-api/&quot;&gt;https://redis.io/docs/manual/programmability/lua-api/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis Clustering Tutorial.), &lt;a href=&quot;https://redis.io/docs/manual/scaling/&quot;&gt;https://redis.io/docs/manual/scaling/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;TypeScript and Node.js with Redis&amp;quot; - (Example: Tutorial from a Node.js or TypeScript focused blog.), [Link to a relevant tutorial]&lt;/li&gt;
&lt;li&gt;&amp;quot;Performance Optimization Techniques for Node.js Applications&amp;quot; - (Example: Article discussing caching as part of broader performance strategies.), [Link to a relevant article]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Backend Development</category><category>Caching</category><category>Performance Optimization</category><category>Node.js</category><category>Redis</category><category>TypeScript</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0055-mastering-caching-strategies-redis-nodejs-typescript/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Scaling Up, Staying Strong: Hands-On AWS CloudFormation Techniques for Building Resilient and Scalable Systems</title><link>https://mkabumattar.com/blog/post/scaling-up-staying-strong-hands-on-aws-cloudformation-techniques-for-building-resilient-and-scalable-systems/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/scaling-up-staying-strong-hands-on-aws-cloudformation-techniques-for-building-resilient-and-scalable-systems/</guid><description>In today&apos;s rapidly evolving digital landscape, building resilient and scalable systems is crucial for businesses to meet growing demands and maintain high availability. Cloud native architecture, combined with the powerful capabilities of Amazon Web Services (AWS), offers an ideal solution for achieving these objectives. In this article, we will explore how AWS CloudFormation, a powerful infrastructure as code tool, enables organizations to build resilient and scalable systems through a hands-on approach.</description><pubDate>Fri, 02 Jun 2023 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction:&lt;/h2&gt;
&lt;p&gt;In today&amp;#39;s rapidly evolving digital landscape, building resilient and scalable systems is crucial for businesses to meet growing demands and maintain high availability. Cloud native architecture, combined with the powerful capabilities of Amazon Web Services (AWS), offers an ideal solution for achieving these objectives. In this article, we will explore how AWS CloudFormation, a powerful infrastructure as code tool, enables organizations to build resilient and scalable systems through a hands-on approach.&lt;/p&gt;
&lt;h2&gt;Understanding Resilience and Scalability in the Cloud&lt;/h2&gt;
&lt;h3&gt;What is Resilience?&lt;/h3&gt;
&lt;p&gt;Resilience, my friends, is the ability of your system to survive the chaos of failures and disruptions without losing its cool. It&amp;#39;s like that one friend who always has a spare umbrella, an emergency snack, and a positive attitude even when everything seems to go wrong. With AWS cloud architecture, you can make your systems as resilient as that friend, with fault isolation, redundancy, and disaster recovery strategies.&lt;/p&gt;
&lt;h3&gt;What is Scalability?&lt;/h3&gt;
&lt;p&gt;Scalability is the superhero power that allows your system to handle ever-increasing workloads like a boss. Imagine your system as a buffet table it needs to expand and contract depending on the number of hungry people lining up. AWS cloud infrastructure gives you the elasticity to scale up or down your resources horizontally and vertically. It&amp;#39;s like having stretchable pants for your servers!&lt;/p&gt;
&lt;h2&gt;The Power of AWS CloudFormation for Resilient and Scalable Systems&lt;/h2&gt;
&lt;h3&gt;Overview of AWS CloudFormation&lt;/h3&gt;
&lt;p&gt;AWS CloudFormation is like a magical wand that lets you conjure AWS resources using simple code spells. It&amp;#39;s like turning a frog into a prince with just a flick of your YAML or JSON wand. CloudFormation automates the creation, update, and deletion of resources, saving you from tedious manual configurations. It&amp;#39;s like having a personal assistant who takes care of all the boring stuff while you focus on the cool magic tricks.&lt;/p&gt;
&lt;h3&gt;Design Principles for Resilient and Scalable Systems&lt;/h3&gt;
&lt;h4&gt;Infrastructure as Code (IaC)&lt;/h4&gt;
&lt;p&gt;In the land of CloudFormation, we embrace the concept of Infrastructure as Code (IaC). It means that we write code to build and manage our infrastructure, just like writing a screenplay for an epic movie. With CloudFormation, you can create reusable templates that bring your infrastructure to life. And the best part? You can version control, test, and replicate your environments easily. It&amp;#39;s like being the director of your own blockbuster infrastructure movie!&lt;/p&gt;
&lt;h4&gt;Resource Organization and Dependency Management&lt;/h4&gt;
&lt;p&gt;Organizing resources and managing dependencies is as crucial as untangling earphones. CloudFormation lets you group resources logically using stacks, just like assembling your favorite LEGO sets. You can define relationships between resources, ensuring they&amp;#39;re created and destroyed in the right order. It&amp;#39;s like playing a game of Jenga, but without the fear of the tower collapsing. Who knew building infrastructure could be this much fun?&lt;/p&gt;
&lt;h2&gt;Hands-On Approach to Building Resilient and Scalable Systems with AWS CloudFormation&lt;/h2&gt;
&lt;h3&gt;Setting Up a Resilient Architecture&lt;/h3&gt;
&lt;h4&gt;Creating an Elastic Load Balancer (ELB) with Auto Scaling&lt;/h4&gt;
&lt;p&gt;Imagine having a personal assistant who distributes your workload and adjusts your resources as needed. Well, an Elastic Load Balancer (ELB) combined with Auto Scaling does exactly that! With CloudFormation, you can create an ELB with Auto Scaling by defining the necessary resources and their configurations. It&amp;#39;s like having your own army of minions to handle traffic and keep your system running smoothly. Say goodbye to downtime and hello to minion-powered resilience!&lt;/p&gt;
&lt;h4&gt;Implementing Multi-AZ Deployment for High Availability&lt;/h4&gt;
&lt;p&gt;Deploying resources across multiple Availability Zones (AZs) is like having secret hideouts in different dimensions. If one hideout gets attacked by aliens, you can quickly teleport to another one, ensuring continuous service. CloudFormation lets you define multi-AZ deployments, spreading your resources across different physical locations. It&amp;#39;s like having a network of secret lairs that keep your system up and running, even during interdimensional chaos. Avengers, assemble!&lt;/p&gt;
&lt;h3&gt;Scaling Systems for Increased Workloads&lt;/h3&gt;
&lt;h4&gt;Autoscaling Groups and Dynamic Scaling&lt;/h4&gt;
&lt;p&gt;Autoscaling Groups are like the magic beans that grow your system when it&amp;#39;s hungry and shrink it when it&amp;#39;s full. With CloudFormation, you can define autoscaling groups and set scaling policies based on CPU utilization, network traffic, or any other metric you fancy. It&amp;#39;s like having a system that expands and contracts like an accordion, perfectly adapting to the workload. So go ahead, let your system dance to the beat of scalability!&lt;/p&gt;
&lt;h4&gt;Leveraging AWS CloudFormation StackSets for Scaling Multiple Stacks&lt;/h4&gt;
&lt;p&gt;Managing multiple accounts and regions can feel like juggling chainsaws while riding a unicycle. But fear not, CloudFormation StackSets are here to save the day! They let you create, update, and delete stacks across multiple accounts and regions with a single template. It&amp;#39;s like having a superhero team that ensures consistent deployments and scalability across your entire organization. Say goodbye to circus acts and hello to StackSet superpowers!&lt;/p&gt;
&lt;h2&gt;Best Practices for Building Resilient and Scalable Systems with AWS CloudFormation&lt;/h2&gt;
&lt;h3&gt;Template Design Best Practices&lt;/h3&gt;
&lt;p&gt;When designing CloudFormation templates, follow these tips to rock your infrastructure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be flexible and reusable by using parameterization. Think of it as having a wardrobe with interchangeable parts for different occasions.&lt;/li&gt;
&lt;li&gt;Make your templates modular to promote reusability and maintainability. It&amp;#39;s like building with LEGO bricks stack them together to create awesome structures!&lt;/li&gt;
&lt;li&gt;Use CloudFormation intrinsic functions to dynamically generate resource configurations. It&amp;#39;s like having a Swiss Army knife that transforms your templates into powerful machines.&lt;/li&gt;
&lt;li&gt;Ensure idempotency, so your templates support updates and rollbacks. It&amp;#39;s like having a magical reset button that undoes any mishaps and brings back harmony to your infrastructure universe.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By adhering to these best practices, you can create robust and adaptable templates that promote resilience and scalability.&lt;/p&gt;
&lt;h2&gt;Testing and Validation&lt;/h2&gt;
&lt;p&gt;Before deploying your infrastructure, put on your quality assurance hat and test your CloudFormation templates. Here are some tips to help you get started:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use the AWS CloudFormation Linter to validate your templates. It&amp;#39;s like having a grammar checker for your code.&lt;/li&gt;
&lt;li&gt;Use the AWS CloudFormation Change Set feature to preview changes before deployment. It&amp;#39;s like having a crystal ball that shows you the future.&lt;/li&gt;
&lt;li&gt;Use the AWS CloudFormation Stack Policy feature to prevent accidental updates. It&amp;#39;s like having a safety lock that prevents your little brother from messing with your LEGO creations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By testing and validating your templates, you can ensure that your infrastructure is resilient and scalable.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the world of cloud computing, building resilient and scalable systems is a necessity. AWS CloudFormation, with its hands-on approach to infrastructure as code, empowers organizations to achieve these objectives efficiently and effectively. By leveraging the power of AWS CloudFormation, you can scale your systems dynamically, handle increasing workloads, and ensure high availability. Embrace a hands-on approach and explore the possibilities of AWS CloudFormation to build resilient and scalable systems for your business.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;AWS CloudFormation User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Well-Architected Framework - Reliability Pillar.), &lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/welcome.html&quot;&gt;https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Well-Architected Framework - Performance Efficiency Pillar (Scalability.), &lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/performance-efficiency-pillar/welcome.html&quot;&gt;https://docs.aws.amazon.com/wellarchitected/latest/performance-efficiency-pillar/welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Infrastructure as Code on AWS.), &lt;a href=&quot;https://aws.amazon.com/devops/infrastructure-as-code/&quot;&gt;https://aws.amazon.com/devops/infrastructure-as-code/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CloudFormation Best Practices.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Elastic Load Balancing User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/elasticloadbalancing/latest/userguide/what-is-load-balancing.html&quot;&gt;https://docs.aws.amazon.com/elasticloadbalancing/latest/userguide/what-is-load-balancing.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon EC2 Auto Scaling User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/autoscaling/ec2/userguide/what-is-amazon-ec2-auto-scaling.html&quot;&gt;https://docs.aws.amazon.com/autoscaling/ec2/userguide/what-is-amazon-ec2-auto-scaling.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Working with AWS CloudFormation StackSets.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/what-is-cfnstacksets.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/what-is-cfnstacksets.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CloudFormation Intrinsic Functions.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using AWS CloudFormation Linter (cfn-lint.), &lt;a href=&quot;https://github.com/aws-cloudformation/cfn-lint&quot;&gt;https://github.com/aws-cloudformation/cfn-lint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Working with Change Sets - AWS CloudFormation.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Preventing Updates to Stack Resources (Stack Policy.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Building Scalable and Resilient Web Applications on AWS&amp;quot; - AWS Whitepaper.), [Search for this whitepaper on aws.amazon.com/whitepapers/]&lt;/li&gt;
&lt;li&gt;&amp;quot;Infrastructure as Code: Managing Servers in the Cloud&amp;quot; by Kief Morris. O&amp;#39;Reilly Media.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Cloud Native DevOps with Kubernetes&amp;quot; by John Arundel and Justin Domingus. (While Kubernetes-focused, it covers cloud-native principles applicable to AWS.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AWS</category><category>Cloud Computing</category><category>DevOps</category><category>Infrastructure as Code</category><category>Scalability</category><category>Resilience</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0054-scaling-up-staying-strong-hands-on-aws-cloudformation-techniques-for-building-resilient-and-scalable-systems/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Unleashing the Magic: Best Practices for Infrastructure Automation in a Cloud Native AWS Environment</title><link>https://mkabumattar.com/blog/post/unleashing-the-magic-best-practices-for-infrastructure-automation-in-a-cloud-native-aws-environment/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/unleashing-the-magic-best-practices-for-infrastructure-automation-in-a-cloud-native-aws-environment/</guid><description>In the realm of Cloud Native AWS environments, mastering infrastructure automation is essential to unlock the full potential of your magical kingdom. From security spells to optimizing performance, this section will reveal the best practices and secret enchantments for achieving seamless infrastructure automation. Join us on this enchanting journey as we explore the spells and rituals that will transform your Cloud Native AWS environment into a well-oiled, high-performing realm.</description><pubDate>Mon, 22 May 2023 10:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction:&lt;/h2&gt;
&lt;p&gt;In the realm of Cloud Native AWS environments, mastering infrastructure automation is essential to unlock the full potential of your magical kingdom. From security spells to optimizing performance, this section will reveal the best practices and secret enchantments for achieving seamless infrastructure automation. Join us on this enchanting journey as we explore the spells and rituals that will transform your Cloud Native AWS environment into a well-oiled, high-performing realm.&lt;/p&gt;
&lt;h2&gt;Ensuring Security and Compliance&lt;/h2&gt;
&lt;h3&gt;Spell of Least Privilege&lt;/h3&gt;
&lt;p&gt;Grant only the necessary permissions to your magical beings, ensuring they have access to perform their designated tasks while minimizing potential risks.&lt;/p&gt;
&lt;h3&gt;Enchanting Security Policies&lt;/h3&gt;
&lt;p&gt;Implement robust security policies and identity and access management practices to safeguard your kingdom from unauthorized access and potential threats.&lt;/p&gt;
&lt;h3&gt;Regular Spell Audits&lt;/h3&gt;
&lt;p&gt;Conduct regular security audits to identify and rectify vulnerabilities in your infrastructure. Perform thorough reviews of your security spells to ensure they align with best practices and industry standards.&lt;/p&gt;
&lt;h2&gt;Implementing CI/CD Pipelines&lt;/h2&gt;
&lt;h3&gt;Automation with Continuous Integration&lt;/h3&gt;
&lt;p&gt;Embrace the power of Continuous Integration (CI) to automate the integration of new spells and configurations into your infrastructure. Leverage tools like AWS CodePipeline and Jenkins to streamline the deployment process.&lt;/p&gt;
&lt;h3&gt;Enchanting Deployment with Continuous Deployment&lt;/h3&gt;
&lt;p&gt;Enhance your automation rituals by implementing Continuous Deployment (CD) practices. This allows for seamless deployment of spells and configurations across different environments.&lt;/p&gt;
&lt;h3&gt;Spell Testing and Quality Assurance&lt;/h3&gt;
&lt;p&gt;Incorporate automated testing spells, such as unit tests and integration tests, to ensure the reliability and stability of your infrastructure changes before deploying them to your kingdom.&lt;/p&gt;
&lt;h2&gt;Monitoring and Scaling&lt;/h2&gt;
&lt;h3&gt;Enchanted Observability&lt;/h3&gt;
&lt;p&gt;Implement robust monitoring and logging spells to gain insights into the performance and health of your infrastructure. Leverage AWS CloudWatch, AWS X-Ray, and other monitoring tools to track and troubleshoot issues.&lt;/p&gt;
&lt;h3&gt;Auto Scaling Magic&lt;/h3&gt;
&lt;p&gt;Harness the power of auto scaling spells to dynamically adjust the resources allocated to your applications based on demand. Ensure your kingdom is always equipped to handle increased traffic and workloads.&lt;/p&gt;
&lt;h2&gt;Performance Optimization&lt;/h2&gt;
&lt;h3&gt;Performance Spell Profiling&lt;/h3&gt;
&lt;p&gt;Cast performance profiling spells to identify bottlenecks and areas for optimization within your infrastructure. Utilize tools like AWS CloudWatch and AWS Trusted Advisor to gather performance data and make informed optimization decisions.&lt;/p&gt;
&lt;h3&gt;Caching and Content Delivery Spells&lt;/h3&gt;
&lt;p&gt;Implement caching and content delivery spells using services like Amazon CloudFront and AWS ElastiCache to boost the performance of your applications, providing faster response times to your kingdom&amp;#39;s users.&lt;/p&gt;
&lt;h2&gt;Cost Management and Optimization&lt;/h2&gt;
&lt;h3&gt;Spell of Cost Allocation&lt;/h3&gt;
&lt;p&gt;Implement resource tagging spells to allocate costs accurately and gain visibility into resource utilization. This enables you to identify cost-saving opportunities and optimize your kingdom&amp;#39;s budget.&lt;/p&gt;
&lt;h3&gt;Reserved Instances and Savings Plans&lt;/h3&gt;
&lt;p&gt;Utilize AWS Reserved Instances and Savings Plans to optimize your infrastructure costs by committing to long-term usage in exchange for significant discounts.&lt;/p&gt;
&lt;h3&gt;Spell of Cost Optimization&lt;/h3&gt;
&lt;p&gt;Regularly review your infrastructure for unused or underutilized resources and decommission them with the wave of your wand. Continuously optimize your infrastructure to maximize cost efficiency without sacrificing performance.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the enchanting world of Cloud Native AWS environments, implementing best practices for infrastructure automation is the key to unleashing the full potential of your magical kingdom. From ensuring security and compliance to implementing CI/CD pipelines and optimizing performance and costs, mastering these spells and rituals will elevate your infrastructure to new heights. Embrace these best practices and watch as your Cloud Native AWS environment flourishes with efficiency, reliability, and scalability.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;AWS Well-Architected Framework.), &lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;https://aws.amazon.com/architecture/well-architected/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Infrastructure as Code on AWS.), &lt;a href=&quot;https://aws.amazon.com/devops/infrastructure-as-code/&quot;&gt;https://aws.amazon.com/devops/infrastructure-as-code/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Security Best Practices Whitepaper.), &lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/aws-security-best-practices/aws-security-best-practices.html&quot;&gt;https://docs.aws.amazon.com/whitepapers/latest/aws-security-best-practices/aws-security-best-practices.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Practicing Continuous Integration and Continuous Delivery on AWS.), &lt;a href=&quot;https://aws.amazon.com/devops/continuous-integration/&quot;&gt;https://aws.amazon.com/devops/continuous-integration/&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://aws.amazon.com/devops/continuous-delivery/&quot;&gt;https://aws.amazon.com/devops/continuous-delivery/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CodePipeline User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/codepipeline/latest/userguide/welcome.html&quot;&gt;https://docs.aws.amazon.com/codepipeline/latest/userguide/welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon CloudWatch User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html&quot;&gt;https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Auto Scaling User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/autoscaling/latest/userguide/Welcome.html&quot;&gt;https://docs.aws.amazon.com/autoscaling/latest/userguide/Welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Cost Management.), &lt;a href=&quot;https://aws.amazon.com/aws-cost-management/&quot;&gt;https://aws.amazon.com/aws-cost-management/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Identity and Access Management (IAM) Best Practices.), &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html&quot;&gt;https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon CloudFront Developer Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot;&gt;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon ElastiCache User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/WhatIs.html&quot;&gt;https://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/WhatIs.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Trusted Advisor.), &lt;a href=&quot;https://aws.amazon.com/premiumsupport/technology/trusted-advisor/&quot;&gt;https://aws.amazon.com/premiumsupport/technology/trusted-advisor/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Cloud Native DevOps with Kubernetes&amp;quot; by John Arundel &amp;amp; Justin Domingus (While Kubernetes-focused, it covers many cloud-native principles.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Infrastructure as Code: Managing Servers in the Cloud&amp;quot; by Kief Morris.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;AWS X-Ray Developer Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html&quot;&gt;https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AWS</category><category>Cloud Native</category><category>DevOps</category><category>Infrastructure Automation</category><category>Best Practices</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0053-unleashing-the-magic-best-practices-for-infrastructure-automation-in-a-cloud-native-aws-environment/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Orchestrating Infrastructure with Terraform: Unleashing the Magic of Infrastructure Provisioning</title><link>https://mkabumattar.com/blog/post/orchestrating-infrastructure-with-terraform-unleashing-the-magic-of-infrastructure-provisioning/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/orchestrating-infrastructure-with-terraform-unleashing-the-magic-of-infrastructure-provisioning/</guid><description>In the realm of infrastructure orchestration, Terraform emerges as a versatile sorcerer&apos;s apprentice, allowing you to create and manage your infrastructure across multiple cloud providers. With Terraform, you can wave your magical wand and provision resources on AWS by writing infrastructure configurations in a declarative language. Join us on a journey through the enchanting world of Terraform and witness the power of infrastructure provisioning magic.</description><pubDate>Mon, 22 May 2023 08:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction:&lt;/h2&gt;
&lt;p&gt;In the realm of infrastructure orchestration, Terraform emerges as a versatile sorcerer&amp;#39;s apprentice, allowing you to create and manage your infrastructure across multiple cloud providers. With Terraform, you can wave your magical wand and provision resources on AWS by writing infrastructure configurations in a declarative language. Join us on a journey through the enchanting world of Terraform and witness the power of infrastructure provisioning magic.&lt;/p&gt;
&lt;h2&gt;The Magic of Terraform&lt;/h2&gt;
&lt;h3&gt;Infrastructure as Code&lt;/h3&gt;
&lt;p&gt;Terraform embraces the concept of Infrastructure as Code (IaC), enabling you to define and manage your infrastructure using code. By codifying your infrastructure configurations, you gain reproducibility, scalability, and version control.&lt;/p&gt;
&lt;h3&gt;Declarative Language&lt;/h3&gt;
&lt;p&gt;Terraform uses a declarative language called HashiCorp Configuration Language (HCL). This language allows you to express your desired infrastructure state without specifying the detailed steps for achieving it, allowing Terraform to work its magic and orchestrate the provisioning process.&lt;/p&gt;
&lt;h2&gt;Terraform in Action&lt;/h2&gt;
&lt;h3&gt;Resource Providers&lt;/h3&gt;
&lt;p&gt;Terraform supports various resource providers, including AWS, Azure, Google Cloud, and many more. With the AWS provider, you can weave your spells and provision AWS resources such as EC2 instances, S3 buckets, and VPCs.&lt;/p&gt;
&lt;h3&gt;Infrastructure Configuration&lt;/h3&gt;
&lt;p&gt;Terraform uses configuration files called &amp;quot;Terraform files&amp;quot; to define your infrastructure. In these files, you specify the resources you want to create, their properties, and any dependencies between them. Terraform analyzes these files to determine the order of resource creation and ensure proper provisioning.&lt;/p&gt;
&lt;h3&gt;Execution Plans&lt;/h3&gt;
&lt;p&gt;Before applying changes, Terraform generates an execution plan that outlines the actions it will take to achieve the desired infrastructure state. This plan helps you preview the changes and ensures that you have full control over the provisioning process.&lt;/p&gt;
&lt;h2&gt;Infrastructure Provisioning with Spells&lt;/h2&gt;
&lt;h3&gt;Init and Apply&lt;/h3&gt;
&lt;p&gt;To work its magic, Terraform requires an initialization step to download the necessary provider plugins and set up the execution environment. Once initialized, you can cast your spell by running the &amp;quot;terraform apply&amp;quot; command, which provisions the defined infrastructure resources.&lt;/p&gt;
&lt;h3&gt;State Management&lt;/h3&gt;
&lt;p&gt;Terraform maintains a state file that keeps track of the current state of your infrastructure. This file allows Terraform to understand the differences between the desired state and the actual state, making it capable of making the necessary changes to achieve the desired state.&lt;/p&gt;
&lt;h2&gt;Spells of Efficiency and Collaboration&lt;/h2&gt;
&lt;h3&gt;Infrastructure Modules&lt;/h3&gt;
&lt;p&gt;Terraform allows you to create reusable modules, which are self-contained configurations that encapsulate a set of resources and their dependencies. These modules promote code reusability, consistency, and efficiency in managing your infrastructure.&lt;/p&gt;
&lt;h3&gt;Version Control and Collaboration&lt;/h3&gt;
&lt;p&gt;By treating Terraform configurations as code, you can store them in version control systems, enabling collaboration among team members and providing a history of changes. This approach ensures proper code management, easy rollbacks, and seamless collaboration.&lt;/p&gt;
&lt;h3&gt;Extending with Providers and Modules&lt;/h3&gt;
&lt;p&gt;Terraform&amp;#39;s extensibility allows you to incorporate additional providers and modules to extend its capabilities. This flexibility empowers you to integrate with different cloud providers and leverage community-created modules for common infrastructure patterns.&lt;/p&gt;
&lt;h2&gt;Best Practices for Terraform&lt;/h2&gt;
&lt;h3&gt;Infrastructure as Code Principles&lt;/h3&gt;
&lt;p&gt;Apply best practices of Infrastructure as Code, such as using version control, documenting changes, and implementing code reviews, to ensure the reliability and maintainability of your Terraform configurations.&lt;/p&gt;
&lt;h3&gt;Terraform Workspaces&lt;/h3&gt;
&lt;p&gt;Utilize Terraform workspaces to manage different environments and maintain separate state files. Workspaces allow you to deploy and manage infrastructure for development, testing, and production environments with ease.&lt;/p&gt;
&lt;h3&gt;Terraform Cloud and CI/CD Integration&lt;/h3&gt;
&lt;p&gt;Consider leveraging Terraform Cloud or integrating Terraform into your CI/CD pipelines to automate the provisioning process, enforce policies, and enable collaboration within your infrastructure provisioning workflows.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Terraform empowers you to wield the power of infrastructure provisioning magic, allowing you to create and manage your infrastructure across multiple cloud providers with ease. By embracing Infrastructure as Code principles and harnessing the declarative nature of Terraform, you can orchestrate your infrastructure effortlessly. Embrace the magic of Terraform and unlock the true potential of infrastructure provisioning.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Terraform by HashiCorp - Official Website.), &lt;a href=&quot;https://www.terraform.io/&quot;&gt;https://www.terraform.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform Documentation.), &lt;a href=&quot;https://developer.hashicorp.com/terraform/docs&quot;&gt;https://developer.hashicorp.com/terraform/docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform AWS Provider Documentation.), &lt;a href=&quot;https://registry.terraform.io/providers/hashicorp/aws/latest/docs&quot;&gt;https://registry.terraform.io/providers/hashicorp/aws/latest/docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Infrastructure as Code - AWS.), &lt;a href=&quot;https://aws.amazon.com/devops/infrastructure-as-code/&quot;&gt;https://aws.amazon.com/devops/infrastructure-as-code/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;HashiCorp Configuration Language (HCL.), &lt;a href=&quot;https://github.com/hashicorp/hcl&quot;&gt;https://github.com/hashicorp/hcl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform Modules - Terraform Documentation.), &lt;a href=&quot;https://developer.hashicorp.com/terraform/language/modules&quot;&gt;https://developer.hashicorp.com/terraform/language/modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform State Management - Terraform Documentation.), &lt;a href=&quot;https://developer.hashicorp.com/terraform/language/state&quot;&gt;https://developer.hashicorp.com/terraform/language/state&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform Workspaces - Terraform Documentation.), &lt;a href=&quot;https://developer.hashicorp.com/terraform/language/workspaces&quot;&gt;https://developer.hashicorp.com/terraform/language/workspaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform Cloud.), &lt;a href=&quot;https://www.hashicorp.com/products/terraform&quot;&gt;https://www.hashicorp.com/products/terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Terraform: Up &amp;amp; Running: Writing Infrastructure as Code&amp;quot; by Yevgeniy Brikman.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;Best Practices for using Terraform - Gruntwork.), &lt;a href=&quot;https://gruntwork.io/guides/foundations/how-to-use-terraform-effectively/&quot;&gt;https://gruntwork.io/guides/foundations/how-to-use-terraform-effectively/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Infrastructure as Code: Managing Servers in the Cloud&amp;quot; by Kief Morris.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;Getting Started with Terraform on AWS - AWS Workshop.), &lt;a href=&quot;https://catalog.workshops.aws/terraform-beginner-to-pro/en-US&quot;&gt;https://catalog.workshops.aws/terraform-beginner-to-pro/en-US&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform Registry (for providers and modules.), &lt;a href=&quot;https://registry.terraform.io/&quot;&gt;https://registry.terraform.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;CI/CD for Infrastructure with Terraform and Jenkins/GitLab CI/GitHub Actions&amp;quot; - (Example: Search for tutorials on this topic.), [Link to a relevant tutorial]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Terraform</category><category>Infrastructure as Code</category><category>DevOps</category><category>Cloud Provisioning</category><category>AWS</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0052-orchestrating-infrastructure-with-terraform-unleashing-the-magic-of-infrastructure-provisioning/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Simplifying Application Deployment with AWS SAM: Unleashing the Power of Serverless Magic</title><link>https://mkabumattar.com/blog/post/simplifying-application-deployment-with-aws-sam-unleashing-the-power-of-serverless-magic/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/simplifying-application-deployment-with-aws-sam-unleashing-the-power-of-serverless-magic/</guid><description>When it comes to deploying serverless applications, AWS SAM (Serverless Application Model) emerges as your trusty sidekick, simplifying the process and harnessing the full power of serverless architecture. SAM templates enable you to define and deploy your serverless functions, APIs, and event sources with ease, turning your serverless wishes into reality.</description><pubDate>Mon, 22 May 2023 06:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction:&lt;/h2&gt;
&lt;p&gt;When it comes to deploying serverless applications, AWS SAM (Serverless Application Model) emerges as your trusty sidekick, simplifying the process and harnessing the full power of serverless architecture. SAM templates enable you to define and deploy your serverless functions, APIs, and event sources with ease, turning your serverless wishes into reality.&lt;/p&gt;
&lt;h2&gt;Understanding AWS SAM&lt;/h2&gt;
&lt;h3&gt;The Magic of Serverless&lt;/h3&gt;
&lt;p&gt;Serverless architecture allows you to focus on writing code without worrying about server management or infrastructure provisioning. It leverages the power of AWS Lambda, enabling you to build scalable and event-driven applications.&lt;/p&gt;
&lt;h3&gt;Meet AWS SAM&lt;/h3&gt;
&lt;p&gt;AWS Serverless Application Model (SAM) is an open-source framework that extends AWS CloudFormation. It provides a simplified syntax and set of tools specifically designed for building and deploying serverless applications.&lt;/p&gt;
&lt;h2&gt;SAM Templates, Granting Serverless Wishes&lt;/h2&gt;
&lt;h3&gt;Structure and Syntax&lt;/h3&gt;
&lt;p&gt;SAM templates use YAML or JSON to define your serverless application&amp;#39;s resources, such as functions, APIs, and event sources. The template structure is concise and intuitive, making it easy to understand and maintain.&lt;/p&gt;
&lt;h3&gt;Defining Serverless Resources&lt;/h3&gt;
&lt;p&gt;With SAM templates, you can declare your AWS Lambda functions, their event sources, and associated permissions. You can also define REST APIs using Amazon API Gateway and configure their endpoints and methods.&lt;/p&gt;
&lt;h3&gt;Streamlined Deployment&lt;/h3&gt;
&lt;p&gt;SAM templates simplify the deployment process by automating the creation of necessary resources and handling dependencies. You can deploy your application using the SAM CLI (Command Line Interface) or integrate it into your CI/CD pipelines.&lt;/p&gt;
&lt;h2&gt;Unlocking the Power of SAM&lt;/h2&gt;
&lt;h3&gt;Local Development and Testing&lt;/h3&gt;
&lt;p&gt;SAM CLI provides a local development environment where you can test and debug your serverless applications before deploying them to the cloud. It allows for faster iteration and debugging, reducing development cycles.&lt;/p&gt;
&lt;h3&gt;Lambda Layers and Packaging&lt;/h3&gt;
&lt;p&gt;SAM enables you to leverage Lambda Layers to share common code and dependencies across multiple functions. Additionally, it simplifies the packaging process by automatically bundling your code and dependencies into deployment packages.&lt;/p&gt;
&lt;h3&gt;Integration with AWS Services&lt;/h3&gt;
&lt;p&gt;SAM seamlessly integrates with other AWS services, such as Amazon DynamoDB, Amazon S3, and Amazon SQS, allowing you to easily incorporate them into your serverless applications. It simplifies resource configuration and enables efficient data processing and storage.&lt;/p&gt;
&lt;h2&gt;Best Practices for SAM in Application Deployment&lt;/h2&gt;
&lt;h3&gt;Modularity and Reusability&lt;/h3&gt;
&lt;p&gt;Design your SAM templates with modularity in mind, creating reusable components and Lambda functions that can be shared across multiple applications. This promotes consistency and reduces duplication of code.&lt;/p&gt;
&lt;h3&gt;Security and Access Control&lt;/h3&gt;
&lt;p&gt;Implement secure practices by configuring IAM (Identity and Access Management) roles and policies for your serverless functions and APIs. Limit permissions to only what is required and implement encryption for sensitive data.&lt;/p&gt;
&lt;h3&gt;Monitoring and Observability&lt;/h3&gt;
&lt;p&gt;Utilize AWS CloudWatch to gain insights into the performance and behavior of your serverless applications. Configure appropriate logging and monitoring metrics to ensure visibility and troubleshoot issues efficiently.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;AWS SAM empowers you to simplify the deployment of serverless applications, turning your serverless wishes into reality. With SAM templates, you can define functions, APIs, and event sources effortlessly, harnessing the power of serverless architecture. Embrace the magic of AWS SAM and unlock the full potential of serverless application development.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;AWS Serverless Application Model (SAM) Developer Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html&quot;&gt;https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS SAM CLI Command Reference.), &lt;a href=&quot;https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference.html&quot;&gt;https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Lambda Developer Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/welcome.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon API Gateway Developer Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html&quot;&gt;https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Serverless Computing? - AWS.), &lt;a href=&quot;https://aws.amazon.com/serverless/&quot;&gt;https://aws.amazon.com/serverless/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CloudFormation User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS SAM Templates - AWS Documentation.), &lt;a href=&quot;https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy.html&quot;&gt;https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using Lambda Layers - AWS Lambda.), &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Security Best Practices for AWS Lambda.), &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/best-practices-security.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/best-practices-security.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Monitoring and Observability for Serverless Applications on AWS.), &lt;a href=&quot;https://aws.amazon.com/serverless/monitoring-and-observability/&quot;&gt;https://aws.amazon.com/serverless/monitoring-and-observability/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS SAM GitHub Repository (for examples and issues.), &lt;a href=&quot;https://github.com/aws/aws-sam-cli&quot;&gt;https://github.com/aws/aws-sam-cli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Serverless Architectures on AWS&amp;quot; by Peter Sbarski and Ajay Nair. Manning Publications.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Building Serverless Applications with AWS SAM&amp;quot; - AWS Online Tech Talks.), [Search for relevant AWS Tech Talks on YouTube or the AWS events page]&lt;/li&gt;
&lt;li&gt;&amp;quot;Infrastructure as Code with AWS SAM&amp;quot; - (Example: Blog post from AWS or a community expert.), [Link to a relevant blog post]&lt;/li&gt;
&lt;li&gt;AWS CloudWatch User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html&quot;&gt;https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AWS</category><category>Serverless</category><category>DevOps</category><category>Infrastructure as Code</category><category>Application Deployment</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0051-simplifying-application-deployment-with-aws-sam-unleashing-the-power-of-serverless-magic/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Leveraging AWS CloudFormation for Infrastructure as Code (IaC): The Mighty Sword of Automation</title><link>https://mkabumattar.com/blog/post/leveraging-aws-cloudformation-for-infrastructure-as-code-iac-the-mighty-sword-of-automation/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/leveraging-aws-cloudformation-for-infrastructure-as-code-iac-the-mighty-sword-of-automation/</guid><description>In the realm of cloud computing, Cloud Native Infrastructure stands tall as a modern sorcery, empowering developers to design and deploy applications tailored explicitly for the cloud. By harnessing the full potential of AWS services, Cloud Native Infrastructure enables the creation of highly scalable, resilient, and efficient applications. It&apos;s like building castles in the sky, aided by an army of cloud-based minions ready to fulfill your every command!</description><pubDate>Mon, 22 May 2023 04:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the realm of Infrastructure as Code (IaC), AWS CloudFormation emerges as a powerful tool, akin to a mighty sword in your infrastructure automation arsenal. With CloudFormation, you can declare your infrastructure using JSON or YAML templates, simplifying the creation and management process. Say goodbye to the days of tangled configurations and manual resource provisioning, and step into the realm of effortless infrastructure management.&lt;/p&gt;
&lt;h2&gt;The Essence of AWS CloudFormation&lt;/h2&gt;
&lt;p&gt;AWS CloudFormation is a service that enables you to define and provision your infrastructure resources in a declarative manner. It allows you to codify your infrastructure requirements using JSON or YAML templates, capturing the desired state of your resources. CloudFormation acts as your trusty guide, ensuring that your infrastructure is created consistently and reliably.&lt;/p&gt;
&lt;h2&gt;Declaring Infrastructure with Templates&lt;/h2&gt;
&lt;h3&gt;JSON or YAML&lt;/h3&gt;
&lt;p&gt;CloudFormation provides flexibility by supporting both JSON and YAML for template definitions. You can choose the format that aligns best with your preferences and needs.&lt;/p&gt;
&lt;h3&gt;Resource Definitions&lt;/h3&gt;
&lt;p&gt;With CloudFormation templates, you define your infrastructure resources, such as Amazon EC2 instances, Amazon RDS databases, and Amazon S3 buckets. You specify properties, dependencies, and configurations for each resource, creating a blueprint for your infrastructure.&lt;/p&gt;
&lt;h3&gt;Stack Management&lt;/h3&gt;
&lt;p&gt;CloudFormation organizes your resources into stacks, enabling you to manage and provision them as a single unit. Stacks allow you to create, update, and delete your infrastructure in a controlled and orchestrated manner.&lt;/p&gt;
&lt;h2&gt;Managing Updates and Rollbacks&lt;/h2&gt;
&lt;h3&gt;Change Sets&lt;/h3&gt;
&lt;p&gt;CloudFormation introduces the concept of change sets, which allow you to preview the impact of proposed changes before applying them. Change sets provide a safety net, enabling you to review modifications, assess potential risks, and ensure that your infrastructure remains intact.&lt;/p&gt;
&lt;h3&gt;Rollback and Recovery&lt;/h3&gt;
&lt;p&gt;In the event of unsuccessful updates, CloudFormation provides rollback mechanisms to revert to the previous stack state. This feature ensures that your infrastructure remains consistent and reliable, even in the face of unexpected issues.&lt;/p&gt;
&lt;h2&gt;The Advantages of CloudFormation in IaC&lt;/h2&gt;
&lt;h3&gt;Automation and Consistency&lt;/h3&gt;
&lt;p&gt;CloudFormation enables automation and repeatability in your infrastructure provisioning process. By defining your infrastructure as code, you eliminate manual configurations, reducing human error and ensuring consistent deployments.&lt;/p&gt;
&lt;h3&gt;Version Control and Collaboration&lt;/h3&gt;
&lt;p&gt;CloudFormation templates can be stored in version control systems, providing a history of changes and facilitating collaboration among team members. Multiple contributors can work together, track modifications, and roll back changes if necessary, ensuring a streamlined and auditable workflow.&lt;/p&gt;
&lt;h3&gt;Modular and Scalable&lt;/h3&gt;
&lt;p&gt;CloudFormation templates allow for modularity and scalability in infrastructure design. You can create reusable components, called nested stacks, that can be shared across multiple templates, promoting consistency and efficiency.&lt;/p&gt;
&lt;h2&gt;Best Practices for CloudFormation in IaC&lt;/h2&gt;
&lt;h3&gt;Parameterization&lt;/h3&gt;
&lt;p&gt;Parameterizing your CloudFormation templates enables flexibility and customization. By externalizing values, you can easily adjust configurations for different environments or use cases without modifying the template itself.&lt;/p&gt;
&lt;h3&gt;Testing and Validation&lt;/h3&gt;
&lt;p&gt;Adopting testing practices for your CloudFormation templates ensures their correctness and reliability. Tools like AWS CloudFormation Linter and AWS CloudFormation Guard can help validate the syntax, structure, and security of your templates.&lt;/p&gt;
&lt;h3&gt;Infrastructure as Code Pipeline&lt;/h3&gt;
&lt;p&gt;Integrating CloudFormation with continuous integration/continuous deployment (CI/CD) pipelines allows for automated and controlled deployments. You can leverage AWS CodePipeline and AWS CodeBuild to automatically test, validate, and deploy your infrastructure changes.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;AWS CloudFormation empowers you to wield the mighty sword of infrastructure automation. By utilizing CloudFormation templates, you can declare your infrastructure resources, manage updates, and maintain a consistent and organized infrastructure kingdom. Embrace the power of CloudFormation in your Infrastructure as Code journey, and witness the transformation of your infrastructure provisioning process.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;AWS CloudFormation User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Infrastructure as Code? - AWS.), &lt;a href=&quot;https://aws.amazon.com/devops/infrastructure-as-code/&quot;&gt;https://aws.amazon.com/devops/infrastructure-as-code/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CloudFormation Template Reference.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-reference.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-reference.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Working with Stacks - AWS CloudFormation.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacks.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacks.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Updating Stacks Using Change Sets - AWS CloudFormation.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CloudFormation Best Practices.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using Parameters - AWS CloudFormation.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CloudFormation Linter (cfn-lint.), &lt;a href=&quot;https://github.com/aws-cloudformation/cfn-lint&quot;&gt;https://github.com/aws-cloudformation/cfn-lint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CloudFormation Guard.), &lt;a href=&quot;https://github.com/aws-cloudformation/cloudformation-guard&quot;&gt;https://github.com/aws-cloudformation/cloudformation-guard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CodePipeline User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/codepipeline/latest/userguide/welcome.html&quot;&gt;https://docs.aws.amazon.com/codepipeline/latest/userguide/welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CodeBuild User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/codebuild/latest/userguide/welcome.html&quot;&gt;https://docs.aws.amazon.com/codebuild/latest/userguide/welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nested Stacks - AWS CloudFormation.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Infrastructure as Code: Managing Servers in the Cloud&amp;quot; by Kief Morris.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;AWS CloudFormation Workshops.), &lt;a href=&quot;https://workshops.aws/categories/Management%20Tools#CloudFormation&quot;&gt;https://workshops.aws/categories/Management%20Tools#CloudFormation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Getting Started with AWS CloudFormation&amp;quot; - AWS Blog.), [Search for relevant getting started guides on the AWS Blog: aws.amazon.com/blogs/mt/]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AWS</category><category>CloudFormation</category><category>Infrastructure as Code</category><category>DevOps</category><category>Cloud Automation</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0050-leveraging-aws-cloudformation-for-infrastructure-as-code-iac-the-mighty-sword-of-automation/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Unleashing the Power of Cloud Native Infrastructure on AWS: Building Castles in the Sky</title><link>https://mkabumattar.com/blog/post/unleashing-the-power-of-cloud-native-infrastructure-on-aws-building-castles-in-the-sky/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/unleashing-the-power-of-cloud-native-infrastructure-on-aws-building-castles-in-the-sky/</guid><description>In the realm of cloud computing, Cloud Native Infrastructure stands tall as a modern sorcery, empowering developers to design and deploy applications tailored explicitly for the cloud. By harnessing the full potential of AWS services, Cloud Native Infrastructure enables the creation of highly scalable, resilient, and efficient applications. It&apos;s like building castles in the sky, aided by an army of cloud-based minions ready to fulfill your every command!</description><pubDate>Mon, 22 May 2023 02:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the realm of cloud computing, Cloud Native Infrastructure stands tall as a modern sorcery, empowering developers to design and deploy applications tailored explicitly for the cloud. By harnessing the full potential of AWS services, Cloud Native Infrastructure enables the creation of highly scalable, resilient, and efficient applications. It&amp;#39;s like building castles in the sky, aided by an army of cloud-based minions ready to fulfill your every command!&lt;/p&gt;
&lt;h2&gt;The Essence of Cloud Native Infrastructure&lt;/h2&gt;
&lt;p&gt;Cloud Native Infrastructure embraces a mindset and approach that embraces the unique characteristics and capabilities of the cloud. It goes beyond simply lifting and shifting applications to the cloud and delves into the intricacies of leveraging cloud services to their fullest extent. With Cloud Native Infrastructure, you can unlock the true power of AWS, enabling applications to seamlessly scale, self-heal, and adapt to changing demands.&lt;/p&gt;
&lt;h2&gt;AWS Services for Cloud Native Applications&lt;/h2&gt;
&lt;h3&gt;AWS Lambda&lt;/h3&gt;
&lt;p&gt;The magical servant of Cloud Native Infrastructure, AWS Lambda allows you to run code without the need for provisioning or managing servers. With Lambda, you can focus solely on your application logic while the service takes care of scaling and availability. It&amp;#39;s like having an army of nimble, serverless minions at your disposal.&lt;/p&gt;
&lt;h3&gt;Amazon DynamoDB&lt;/h3&gt;
&lt;p&gt;A powerful and fully managed NoSQL database service, DynamoDB offers limitless scalability, low latency, and seamless replication across multiple regions. With DynamoDB, you can store and retrieve data with ease, ensuring the robustness and resilience of your cloud-native applications.&lt;/p&gt;
&lt;h3&gt;Amazon S3&lt;/h3&gt;
&lt;p&gt;The mighty storage solution in the AWS realm, Amazon S3 provides scalable object storage with high durability and availability. It serves as the perfect repository for storing and retrieving data, media files, backups, and much more, forming an essential building block of cloud-native architectures.&lt;/p&gt;
&lt;h2&gt;Architectural Considerations for Cloud Native AWS Environments&lt;/h2&gt;
&lt;h3&gt;Microservices and Serverless Architecture&lt;/h3&gt;
&lt;p&gt;Cloud Native Infrastructure encourages the adoption of microservices and serverless architecture patterns. Breaking down applications into smaller, independent services allows for better scalability, fault isolation, and independent deployment. Serverless components further enhance the agility and efficiency of the architecture, eliminating the need for server management.&lt;/p&gt;
&lt;h3&gt;Resilience and Fault Tolerance&lt;/h3&gt;
&lt;p&gt;Cloud Native Infrastructure promotes building applications that are resilient to failures. By leveraging AWS services like Elastic Load Balancing, Auto Scaling, and Amazon Route 53, you can ensure high availability, fault tolerance, and seamless traffic distribution across multiple regions and availability zones.&lt;/p&gt;
&lt;h3&gt;Observability and Monitoring&lt;/h3&gt;
&lt;p&gt;In a Cloud Native AWS environment, observability plays a crucial role in maintaining the health and performance of applications. AWS services like Amazon CloudWatch, AWS X-Ray, and AWS CloudTrail provide powerful monitoring and logging capabilities, enabling you to gain deep insights into the behavior of your applications and infrastructure.&lt;/p&gt;
&lt;h2&gt;Cloud Native Infrastructure and Infrastructure as Code (IaC)&lt;/h2&gt;
&lt;p&gt;Cloud Native Infrastructure aligns seamlessly with Infrastructure as Code (IaC) principles. By treating infrastructure as code, you can provision, configure, and manage your cloud resources in a repeatable, consistent, and automated manner. Tools like AWS CloudFormation, AWS SAM, and Terraform enable you to define your infrastructure as code, simplifying deployment, maintenance, and scalability.&lt;/p&gt;
&lt;h2&gt;Embracing the Magic of Cloud Native Infrastructure on AWS&lt;/h2&gt;
&lt;p&gt;Cloud Native Infrastructure on AWS opens up a world of possibilities for developers and organizations. By embracing the power of AWS services and adopting cloud-native design principles, you can build applications that are scalable, resilient, and cost-effective. The sky&amp;#39;s the limit when it comes to leveraging the magic of Cloud Native Infrastructure!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Cloud Native Infrastructure on AWS is a transformative approach to application design and deployment. By embracing the unique capabilities of AWS services, developers can unleash the full potential of the cloud. From serverless minions like AWS Lambda to robust storage options like Amazon DynamoDB and Amazon S3, Cloud Native Infrastructure empowers you to build castles in the sky. So, embrace the magic of Cloud Native Infrastructure and unlock the true power of AWS!&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What is Cloud Native? - AWS.), &lt;a href=&quot;https://aws.amazon.com/what-is/cloud-native/&quot;&gt;https://aws.amazon.com/what-is/cloud-native/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cloud Native Computing Foundation (CNCF) - Definition.), &lt;a href=&quot;https://github.com/cncf/toc/blob/main/DEFINITION.md&quot;&gt;https://github.com/cncf/toc/blob/main/DEFINITION.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Lambda Developer Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/welcome.html&quot;&gt;https://docs.aws.amazon.com/lambda/latest/dg/welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon DynamoDB Developer Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html&quot;&gt;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon S3 User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html&quot;&gt;https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microservices on AWS.), &lt;a href=&quot;https://aws.amazon.com/microservices/&quot;&gt;https://aws.amazon.com/microservices/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Serverless on AWS.), &lt;a href=&quot;https://aws.amazon.com/serverless/&quot;&gt;https://aws.amazon.com/serverless/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Well-Architected Framework.), &lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;https://aws.amazon.com/architecture/well-architected/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Infrastructure as Code on AWS.), &lt;a href=&quot;https://aws.amazon.com/devops/infrastructure-as-code/&quot;&gt;https://aws.amazon.com/devops/infrastructure-as-code/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CloudFormation User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform on AWS.), &lt;a href=&quot;https://developer.hashicorp.com/terraform/tutorials/aws-get-started&quot;&gt;https://developer.hashicorp.com/terraform/tutorials/aws-get-started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon CloudWatch User Guide (Observability.), &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html&quot;&gt;https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS X-Ray Developer Guide (Observability.), &lt;a href=&quot;https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html&quot;&gt;https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Elastic Load Balancing User Guide (Resilience.), &lt;a href=&quot;https://docs.aws.amazon.com/elasticloadbalancing/latest/userguide/what-is-load-balancing.html&quot;&gt;https://docs.aws.amazon.com/elasticloadbalancing/latest/userguide/what-is-load-balancing.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Amazon EC2 Auto Scaling User Guide (Resilience/Scalability.), &lt;a href=&quot;https://docs.aws.amazon.com/autoscaling/ec2/userguide/what-is-amazon-ec2-auto-scaling.html&quot;&gt;https://docs.aws.amazon.com/autoscaling/ec2/userguide/what-is-amazon-ec2-auto-scaling.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AWS</category><category>Cloud Native</category><category>Serverless</category><category>DevOps</category><category>Infrastructure as Code</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0049-unleashing-the-power-of-cloud-native-infrastructure-on-aws-building-castles-in-the-sky/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Understanding Infrastructure as Code (IaC): Unleashing the Magic of Code-Driven Infrastructure Management</title><link>https://mkabumattar.com/blog/post/understanding-infrastructure-as-code-iac-unleashing-the-magic-of-code-driven-infrastructure-management/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/understanding-infrastructure-as-code-iac-unleashing-the-magic-of-code-driven-infrastructure-management/</guid><description>In the realm of modern technology, infrastructure management has undergone a revolutionary transformation with the emergence of Infrastructure as Code (IaC). Imagine having the power to conjure and control your entire infrastructure using the magic of code. Welcome to the enchanting world of IaC, where manual configurations and tedious clicking are replaced with the elegance and efficiency of code-driven infrastructure management.</description><pubDate>Mon, 22 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the realm of modern technology, infrastructure management has undergone a revolutionary transformation with the emergence of Infrastructure as Code (IaC). Imagine having the power to conjure and control your entire infrastructure using the magic of code. Welcome to the enchanting world of IaC, where manual configurations and tedious clicking are replaced with the elegance and efficiency of code-driven infrastructure management.&lt;/p&gt;
&lt;h2&gt;The Essence of IaC&lt;/h2&gt;
&lt;p&gt;In this digital era, IaC serves as your very own magical spellbook for infrastructure. It enables you to define and manage every aspect of your infrastructure using code, bringing immense benefits and unparalleled control. Say goodbye to error-prone manual interventions and hello to the wonders of automation.&lt;/p&gt;
&lt;h2&gt;Benefits of IaC&lt;/h2&gt;
&lt;h3&gt;Reproducibility&lt;/h3&gt;
&lt;p&gt;With IaC, you can reproduce your infrastructure effortlessly. The code serves as a blueprint, enabling you to create identical environments with a simple incantation. This consistency ensures reliable and predictable deployments, making troubleshooting a breeze.&lt;/p&gt;
&lt;h3&gt;Scalability&lt;/h3&gt;
&lt;p&gt;Scaling your infrastructure becomes as simple as modifying a few lines of code. IaC allows you to easily adjust the capacity of your resources to meet the demands of your applications. Whether it&amp;#39;s increasing the number of servers or expanding storage capacity, IaC empowers you to scale your infrastructure seamlessly.&lt;/p&gt;
&lt;h3&gt;Time-Saving Enchantments&lt;/h3&gt;
&lt;p&gt;Gone are the days of laborious manual configurations. IaC automates the provisioning and management of your infrastructure, freeing up valuable time for more strategic endeavors. With code-driven infrastructure, you can focus on innovation and optimizing your systems rather than being consumed by repetitive tasks.&lt;/p&gt;
&lt;h2&gt;Implementing IaC&lt;/h2&gt;
&lt;h3&gt;Declarative vs. Imperative&lt;/h3&gt;
&lt;p&gt;IaC can be implemented in either a declarative or imperative manner. The declarative approach involves specifying the desired state of the infrastructure, allowing the system to determine the necessary actions to achieve that state. On the other hand, the imperative approach involves defining explicit steps to be executed, guiding the system through the desired changes.&lt;/p&gt;
&lt;h3&gt;Popular IaC Tools&lt;/h3&gt;
&lt;p&gt;There is an array of powerful IaC tools available, each with its own unique strengths. Tools such as AWS CloudFormation, Terraform, and Ansible provide intuitive ways to define and manage infrastructure using code. These tools offer robust features, extensive resource support, and integrations with popular cloud providers.&lt;/p&gt;
&lt;h2&gt;The Enchanting Advantages of IaC&lt;/h2&gt;
&lt;h3&gt;Collaboration and Version Control&lt;/h3&gt;
&lt;p&gt;With IaC, collaboration among team members becomes effortless. Infrastructure configurations can be stored in version control systems, allowing multiple contributors to work together harmoniously. Changes can be tracked, reviewed, and rolled back if needed, ensuring a smooth and auditable workflow.&lt;/p&gt;
&lt;h3&gt;Infrastructure Testing and Validation&lt;/h3&gt;
&lt;p&gt;IaC enables automated testing of infrastructure configurations, ensuring that changes are error-free before deployment. By validating the code through testing pipelines, you can detect potential issues early on, guaranteeing stability and reliability in your infrastructure.&lt;/p&gt;
&lt;h3&gt;Disaster Recovery and High Availability&lt;/h3&gt;
&lt;p&gt;IaC makes disaster recovery and high availability strategies more attainable. By codifying the desired state of your infrastructure, you can easily recreate and recover your entire environment in case of failures. IaC also allows you to implement redundancy and fault-tolerant architectures, ensuring uninterrupted services even during unforeseen events.&lt;/p&gt;
&lt;h2&gt;Embracing the Magic of IaC&lt;/h2&gt;
&lt;p&gt;As technology evolves, the significance of IaC continues to grow. Organizations across industries are recognizing its power to streamline operations, reduce human errors, and increase agility. Embracing IaC requires a shift in mindset and a commitment to continuous learning. By investing in the mastery of IaC, you can unlock a world of opportunities to build robust, scalable, and efficient infrastructure.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Infrastructure as Code (IaC) is a game-changer in the world of infrastructure management. By treating infrastructure as code, you gain the ability to automate, scale, and reproduce your infrastructure with ease. The time-saving enchantments, scalability, and reproducibility offered by IaC empower you to focus on innovation and strategic initiatives. So, grab your magical spellbook of code and embark on a journey to master the art of Infrastructure as Code, where the possibilities are limitless.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What is Infrastructure as Code? - AWS.), &lt;a href=&quot;https://aws.amazon.com/devops/infrastructure-as-code/&quot;&gt;https://aws.amazon.com/devops/infrastructure-as-code/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Terraform by HashiCorp - Official Website.), &lt;a href=&quot;https://www.terraform.io/&quot;&gt;https://www.terraform.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS CloudFormation User Guide.), &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&quot;&gt;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ansible Documentation.), &lt;a href=&quot;https://docs.ansible.com/&quot;&gt;https://docs.ansible.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Infrastructure as Code: Managing Servers in the Cloud&amp;quot; by Kief Morris. O&amp;#39;Reilly Media.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;Terraform: Up &amp;amp; Running: Writing Infrastructure as Code&amp;quot; by Yevgeniy Brikman. O&amp;#39;Reilly Media.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;Declarative vs. Imperative IaC - Microsoft Learn.), &lt;a href=&quot;https://learn.microsoft.com/en-us/devops/deliver/what-is-infrastructure-as-code#declarative-vs-imperative&quot;&gt;https://learn.microsoft.com/en-us/devops/deliver/what-is-infrastructure-as-code#declarative-vs-imperative&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Twelve-Factor App - (Principles relevant to IaC and modern app development.), &lt;a href=&quot;https://12factor.net/&quot;&gt;https://12factor.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Git - Version Control System.), &lt;a href=&quot;https://git-scm.com/&quot;&gt;https://git-scm.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Continuous Integration (CI) and Continuous Delivery (CD) - Atlassian.), &lt;a href=&quot;https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment&quot;&gt;https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;The Phoenix Project: A Novel About IT, DevOps, and Helping Your Business Win&amp;quot; by Gene Kim, Kevin Behr, and George Spafford. (Context for DevOps and IaC.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;Martin Fowler - InfrastructureAsCode.), &lt;a href=&quot;https://martinfowler.com/bliki/InfrastructureAsCode.html&quot;&gt;https://martinfowler.com/bliki/InfrastructureAsCode.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IaC Best Practices - (Example: Article from a reputable DevOps blog or community like DZone, InfoQ, or a major cloud provider&amp;#39;s blog.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;What is Infrastructure as Code? An Introduction&amp;quot; - Red Hat.), &lt;a href=&quot;https://www.redhat.com/en/topics/automation/what-is-infrastructure-as-code-iac&quot;&gt;https://www.redhat.com/en/topics/automation/what-is-infrastructure-as-code-iac&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Benefits of Infrastructure as Code&amp;quot; - HashiCorp.), &lt;a href=&quot;https://www.hashicorp.com/resources/what-is-infrastructure-as-code&quot;&gt;https://www.hashicorp.com/resources/what-is-infrastructure-as-code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Infrastructure as Code</category><category>DevOps</category><category>Cloud Computing</category><category>Automation</category><category>Software Engineering</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0048-understanding-infrastructure-as-code-iac-unleashing-the-magic-of-code-driven-infrastructure-management/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Mastering Infrastructure Automation: Harnessing the Power of IaC in a Cloud Native AWS Environment</title><link>https://mkabumattar.com/blog/post/mastering-infrastructure-automation-harnessing-the-power-of-iac-in-a-cloud-native-aws-environment/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/mastering-infrastructure-automation-harnessing-the-power-of-iac-in-a-cloud-native-aws-environment/</guid><description>In today&apos;s fast-paced digital landscape, building scalable and resilient systems is crucial for businesses to meet growing demands and maintain high availability. Cloud native infrastructure, combined with the powerful capabilities of Amazon Web Services (AWS), offers an ideal solution for achieving these objectives.</description><pubDate>Sun, 21 May 2023 22:27:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Hey there, fellow tech enthusiasts! Welcome to another exciting adventure in the world of infrastructure automation. Today, we&amp;#39;re diving deep into the powerful realm of Infrastructure as Code (IaC) and how it works wonders in a Cloud Native AWS environment. So, fasten your seatbelts and get ready for a journey filled with automation, cloud-native infrastructure, and a sprinkle of humor along the way!&lt;/p&gt;
&lt;h2&gt;Understanding Infrastructure as Code (IaC)&lt;/h2&gt;
&lt;p&gt;Picture this IaC is like having your own magical spellbook for infrastructure. It allows you to define and manage your entire infrastructure using code. No more manual clicking and typing, huzzah! With IaC, you can treat your infrastructure like a piece of code, and enjoy benefits such as reproducibility, scalability, and time-saving enchantments.&lt;/p&gt;
&lt;p&gt;To Read more about IaC, check out our blog post &lt;a href=&quot;/blog/post/understanding-infrastructure-as-code-iac-unleashing-the-magic-of-code-driven-infrastructure-management&quot;&gt;&lt;strong&gt;Understanding Infrastructure as Code (IaC): Unleashing the Magic of Code-Driven Infrastructure Management.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Cloud Native Infrastructure on AWS&lt;/h2&gt;
&lt;p&gt;Cloud Native Infrastructure is the modern sorcery of designing applications specifically for the cloud. It&amp;#39;s all about leveraging the full potential of AWS services to create highly scalable and resilient applications. Imagine building castles in the sky with the help of services like AWS Lambda, Amazon DynamoDB, and Amazon S3. It&amp;#39;s like having an army of cloud-based minions ready to do your bidding!&lt;/p&gt;
&lt;p&gt;To Read more about Cloud Native Infrastructure, check out our blog post &lt;a href=&quot;/blog/post/unleashing-the-power-of-cloud-native-infrastructure-on-aws-building-castles-in-the-sky&quot;&gt;&lt;strong&gt;Unleashing the Power of Cloud Native Infrastructure on AWS: Building Castles in the Sky.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Leveraging AWS CloudFormation for IaC&lt;/h2&gt;
&lt;p&gt;Enter AWS CloudFormation, the mighty sword in your infrastructure automation arsenal. CloudFormation allows you to declare your infrastructure using JSON or YAML templates, transforming your infrastructure creation process into a piece of cake. No more pulling your hair out trying to remember the exact order of resource creation! Plus, with CloudFormation, you can easily manage updates, rollback changes, and maintain a tidy and organized infrastructure kingdom.&lt;/p&gt;
&lt;p&gt;To Read more about AWS CloudFormation, check out our blog post &lt;a href=&quot;/blog/post/leveraging-aws-cloudformation-for-infrastructure-as-code-iac-the-mighty-sword-of-automation&quot;&gt;&lt;strong&gt;Leveraging AWS CloudFormation for Infrastructure as Code (IaC): The Mighty Sword of Automation.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Simplifying Application Deployment with AWS SAM&lt;/h2&gt;
&lt;p&gt;Here comes the star of the serverless show – AWS Serverless Application Model (SAM). SAM provides a simplified way to define and deploy serverless applications on AWS Lambda. It&amp;#39;s like having a personal assistant that handles all the nitty-gritty details of deploying your serverless creations. With SAM, you can focus on writing code and let the magic happen!&lt;/p&gt;
&lt;p&gt;To Read more about AWS SAM, check out our blog post &lt;a href=&quot;/blog/post/simplifying-application-deployment-with-aws-sam-unleashing-the-power-of-serverless-magic&quot;&gt;&lt;strong&gt;Simplifying Application Deployment with AWS SAM: Unleashing the Power of Serverless Magic.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Orchestrating Infrastructure with Terraform&lt;/h2&gt;
&lt;p&gt;Now, let&amp;#39;s introduce our Swiss Army knife of infrastructure automation – Terraform. It&amp;#39;s an open-source tool that allows you to define and manage your infrastructure as code across multiple cloud providers, including AWS. Think of it as the James Bond of IaC, handling missions in style. With Terraform, you&amp;#39;ll be orchestrating your infrastructure with elegance and finesse.&lt;/p&gt;
&lt;p&gt;To Read more about Terraform, check out our blog post &lt;a href=&quot;/blog/post/orchestrating-infrastructure-with-terraform-unleashing-the-magic-of-infrastructure-provisioning&quot;&gt;&lt;strong&gt;Orchestrating Infrastructure with Terraform: Unleashing the Magic of Infrastructure Provisioning.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Best Practices for Infrastructure Automation in a Cloud Native AWS Environment&lt;/h2&gt;
&lt;p&gt;Now, let&amp;#39;s dive into the secret spells and enchantments for mastering infrastructure automation. We&amp;#39;ll cover everything from ensuring the security of your magical kingdom to implementing CI/CD pipelines that work like well-oiled broomsticks. We&amp;#39;ll even explore how to tame the wild dragons of cost management and optimize your infrastructure for peak performance.&lt;/p&gt;
&lt;p&gt;To Read more about Best Practices for Infrastructure Automation, check out our blog post &lt;a href=&quot;/blog/post/unleashing-the-magic-best-practices-for-infrastructure-automation-in-a-cloud-native-aws-environment&quot;&gt;&lt;strong&gt;Unleashing the Magic: Best Practices for Infrastructure Automation in a Cloud Native AWS Environment.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations, brave wizards of automation! You&amp;#39;ve embarked on a journey to master the art of Infrastructure as Code in a Cloud Native AWS environment. We&amp;#39;ve covered the basics of IaC, danced with Cloud Native Infrastructure, and wielded the powers of AWS CloudFormation, SAM, and Terraform. Remember, the path to automation may be filled with challenges, but with the right tools and a touch of magic, you can conquer any infrastructure task!&lt;/p&gt;
&lt;p&gt;So, go forth, automate with confidence, and unlock the true power of IaC. Don&amp;#39;t forget to check out our other magical adventures, such as &lt;a href=&quot;/blog/post/mastering-aws-architecture-a-comprehensive-guide-to-the-well-architected-framework&quot;&gt;&lt;strong&gt;Mastering AWS Architecture: A Comprehensive Guide to the Well-Architected Framework&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;/blog/post/how-to-avoid-common-cloud-services-mistakes&quot;&gt;&lt;strong&gt;How to Avoid Common Cloud Services Mistakes&lt;/strong&gt;&lt;/a&gt;, and &lt;a href=&quot;/blog/post/how-to-setup-bastion-host-on-aws-using-cloudformation-template&quot;&gt;&lt;strong&gt;How to Setup a Bastion Host on AWS using CloudFormation Template.&lt;/strong&gt;&lt;/a&gt; Until our paths cross again, keep coding, stay curious, and never stop exploring the enchanted realms of technology!&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&quot;&gt;AWS CloudFormation User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html&quot;&gt;AWS Serverless Application Model (SAM) Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.hashicorp.com/terraform/docs&quot;&gt;Terraform by HashiCorp - Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/devops/infrastructure-as-code/&quot;&gt;What is Infrastructure as Code? - AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/what-is/cloud-native/&quot;&gt;What is Cloud Native? - AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;AWS Well-Architected Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/understanding-infrastructure-as-code-iac-unleashing-the-magic-of-code-driven-infrastructure-management&quot;&gt;Understanding Infrastructure as Code (IaC): Unleashing the Magic of Code-Driven Infrastructure Management.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/unleashing-the-power-of-cloud-native-infrastructure-on-aws-building-castles-in-the-sky&quot;&gt;Unleashing the Power of Cloud Native Infrastructure on AWS: Building Castles in the Sky.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/leveraging-aws-cloudformation-for-infrastructure-as-code-iac-the-mighty-sword-of-automation&quot;&gt;Leveraging AWS CloudFormation for Infrastructure as Code (IaC): The Mighty Sword of Automation.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/simplifying-application-deployment-with-aws-sam-unleashing-the-power-of-serverless-magic&quot;&gt;Simplifying Application Deployment with AWS SAM: Unleashing the Power of Serverless Magic.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/orchestrating-infrastructure-with-terraform-unleashing-the-magic-of-infrastructure-provisioning&quot;&gt;Orchestrating Infrastructure with Terraform: Unleashing the Magic of Infrastructure Provisioning.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/unleashing-the-magic-best-practices-for-infrastructure-automation-in-a-cloud-native-aws-environment&quot;&gt;Unleashing the Magic: Best Practices for Infrastructure Automation in a Cloud Native AWS Environment.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/mastering-aws-architecture-a-comprehensive-guide-to-the-well-architected-framework&quot;&gt;Mastering AWS Architecture: A Comprehensive Guide to the Well-Architected Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/how-to-avoid-common-cloud-services-mistakes&quot;&gt;How to Avoid Common Cloud Services Mistakes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/how-to-setup-bastion-host-on-aws-using-cloudformation-template&quot;&gt;How to Setup a Bastion Host on AWS using CloudFormation Template.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>Infrastructure as Code</category><category>Cloud Native</category><category>DevOps</category><category>Automation</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0047-mastering-infrastructure-automation-harnessing-the-power-of-iac-in-a-cloud-native-aws-environment/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Decoding REST API Architecture: A Comprehensive Guide for Developers</title><link>https://mkabumattar.com/blog/post/decoding-rest-api-architecture-a-comprehensive-guide-for-developers/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/decoding-rest-api-architecture-a-comprehensive-guide-for-developers/</guid><description>Hey there, fellow developers! Buckle up because we&apos;re about to dive into the crazy world of REST API architecture.</description><pubDate>Sat, 20 May 2023 20:27:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Hey there, fellow developers! Buckle up because we&amp;#39;re about to dive into the crazy world of REST API architecture. Prepare to decode the mysterious differences between REST API and RESTful API. In this comprehensive guide, we&amp;#39;ll make sense of REST&amp;#39;s principles and shed some light on RESTful APIs. Let&amp;#39;s go on this wild ride together!&lt;/p&gt;
&lt;h2&gt;What is the Difference Between REST API and RESTful API?&lt;/h2&gt;
&lt;p&gt;Alright, so picture this: REST API and RESTful API walk into a bar. They look similar, talk the same language, but boy, do they have different personalities! REST API is the general term for any API that follows REST&amp;#39;s principles. On the other hand, RESTful API is like the rule-abiding citizen who strictly adheres to REST&amp;#39;s constraints. They&amp;#39;re like twins, but one&amp;#39;s the rebel and the other is the goody-two-shoes.&lt;/p&gt;
&lt;h2&gt;Why is REST API Called RESTful API?&lt;/h2&gt;
&lt;p&gt;You might be wondering why REST API is called RESTful API. Well, think of it like this: RESTful API is the API version of your friend who follows all the rules. They&amp;#39;re super diligent and always on their best behavior. RESTful APIs strictly follow REST&amp;#39;s principles, making them scalable, reliable, and the life of the party when it comes to interoperability between different systems.&lt;/p&gt;
&lt;h2&gt;What is REST and Explaining RESTful APIs?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Statelessness:&lt;/strong&gt; RESTful APIs are like Zen masters they&amp;#39;re completely stateless. Each client request carries all the necessary information for the server to understand and process it. No need for the server to store session-specific data. It&amp;#39;s all about being scalable and reliable, baby!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Uniform Interface:&lt;/strong&gt; RESTful APIs follow a uniform interface, like your favorite superhero with a standard set of moves. They use HTTP methods like GET, POST, PUT, and DELETE to interact with resources. And don&amp;#39;t forget those unique URIs (Uniform Resource Identifiers) for identifying resources. It&amp;#39;s like their secret handshake!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Client-Server Architecture:&lt;/strong&gt; REST separates the client from the server, just like separating your boss from your office shenanigans. The client takes care of the user interface and experience, while the server handles the heavy lifting of data storage and processing. It&amp;#39;s teamwork at its finest!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cacheability:&lt;/strong&gt; RESTful APIs love to party with HTTP caching mechanisms. By specifying cache-related headers, they make responses cacheable, boosting performance, and lightening the server&amp;#39;s load. It&amp;#39;s like giving everyone a chance to catch their breath between dances!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Layered System:&lt;/strong&gt; REST is all about being versatile, just like those fancy layered cakes. It allows multiple layers, like load balancers and firewalls, to exist between the client and the server. This layered architecture brings scalability, security, and flexibility to the party!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Examples of REST API and RESTful APIs&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s spice things up with some examples! Imagine we&amp;#39;re running an e-commerce application. Here are two scenarios of retrieving product information:&lt;/p&gt;
&lt;h3&gt;REST API Example:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Endpoint: &lt;strong&gt;&lt;code&gt;GET /products&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Description: Picture this: you want all the products, and you want them now! This endpoint retrieves a list of all the products you desire.&lt;/li&gt;
&lt;li&gt;Response: Get ready for a JSON array containing those fabulous product objects!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;RESTful API Example:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Endpoint: &lt;strong&gt;&lt;code&gt;GET /products/{id}&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Description: So, you have your eyes set on a specific product, huh? No worries! Just provide the product ID, and voila! This endpoint retrieves the specific product you&amp;#39;re drooling over.&lt;/li&gt;
&lt;li&gt;Response: Brace yourself for that beautiful JSON object representing your dream product.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both examples follow REST&amp;#39;s principles by using the proper HTTP method (GET) and providing the necessary resource identifiers (URL paths). It&amp;#39;s like having a backstage pass to the API concert!&lt;/p&gt;
&lt;h2&gt;Difference Between Web API and RESTful Services&lt;/h2&gt;
&lt;p&gt;Now, let&amp;#39;s talk about the cool kids on the block: web APIs and RESTful services. Web API is the umbrella term for any interface that lets different software systems party together over the web. It&amp;#39;s a wild world out there with various architectural styles, including RESTful services. While RESTful services strictly follow REST&amp;#39;s principles, not all web APIs do. Some prefer other technologies like SOAP, XML-RPC, or even GraphQL. It&amp;#39;s like a never-ending battle of the APIs!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations, fellow developers! You&amp;#39;ve successfully decoded the secrets of REST API architecture. Understanding the differences between REST API and RESTful API is like knowing which party is wild and which is a bit more tamed. By embracing REST&amp;#39;s principles, you can build scalable, future-proof applications that rock the stage of efficient communication between systems.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re hungry for more API knowledge, check out our blog post on &lt;a href=&quot;/blog/post/restful-api-vs-graphql-which-api-is-the-right-choice-for-your-project&quot;&gt;RESTful API vs. GraphQL: Which API is the Right Choice for Your Project?&lt;/a&gt;. It&amp;#39;s like a backstage pass to another epic API showdown!&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Fielding, Roy T. &amp;quot;Architectural Styles and the Design of Network-based Software Architectures.&amp;quot; Doctoral dissertation, University of California, Irvine, 2000. (The origin of REST.), &lt;a href=&quot;https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm&quot;&gt;https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;What is REST?&amp;quot; - REST API Tutorial.), &lt;a href=&quot;https://restfulapi.net/&quot;&gt;https://restfulapi.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Understanding RESTful APIs&amp;quot; - Smashing Magazine.), &lt;a href=&quot;https://www.smashingmagazine.com/2018/01/understanding-restful-apis/&quot;&gt;https://www.smashingmagazine.com/2018/01/understanding-restful-apis/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;REST API Design Rulebook&amp;quot; - Mark Masse. O&amp;#39;Reilly Media.), [Link to a reputable source for the book or summary]&lt;/li&gt;
&lt;li&gt;&amp;quot;HTTP Methods for RESTful Services&amp;quot; - REST API Tutorial.), &lt;a href=&quot;https://restfulapi.net/http-methods/&quot;&gt;https://restfulapi.net/http-methods/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Statelessness in REST APIs&amp;quot; - GeeksforGeeks.), &lt;a href=&quot;https://www.geeksforgeeks.org/statelessness-in-rest-apis/&quot;&gt;https://www.geeksforgeeks.org/statelessness-in-rest-apis/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Uniform Interface Constraint in REST&amp;quot; - REST API Tutorial.), &lt;a href=&quot;https://restfulapi.net/uniform-interface/&quot;&gt;https://restfulapi.net/uniform-interface/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Client-Server Architecture&amp;quot; - MDN Web Docs.), &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview#client-server_architecture&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview#client-server_architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;HTTP Caching&amp;quot; - MDN Web Docs.), &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Layered System Constraint in REST&amp;quot; - REST API Tutorial.), &lt;a href=&quot;https://restfulapi.net/layered-system/&quot;&gt;https://restfulapi.net/layered-system/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;What is a Web API?&amp;quot; - MuleSoft.), &lt;a href=&quot;https://www.mulesoft.com/resources/api/what-is-a-web-api&quot;&gt;https://www.mulesoft.com/resources/api/what-is-a-web-api&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;API Design Best Practices&amp;quot; - Swagger/OpenAPI.), &lt;a href=&quot;https://swagger.io/resources/articles/best-practices-in-api-design/&quot;&gt;https://swagger.io/resources/articles/best-practices-in-api-design/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Richardson Maturity Model&amp;quot; (Steps toward the glory of REST.), &lt;a href=&quot;https://martinfowler.com/articles/richardsonMaturityModel.html&quot;&gt;https://martinfowler.com/articles/richardsonMaturityModel.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>API Development</category><category>Web Architecture</category><category>Software Engineering</category><category>Backend Development</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0046-decoding-rest-api-architecture-a-comprehensive-guide-for-developers/hero.jpg" length="0" type="image/jpeg"/></item><item><title>TypeScript vs. JSDoc: Exploring the Pros and Cons of Static Type Checking in JavaScript</title><link>https://mkabumattar.com/blog/post/typescript-vs-jsdoc-exploring-the-pros-and-cons-of-static-type-checking-in-javascript/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/typescript-vs-jsdoc-exploring-the-pros-and-cons-of-static-type-checking-in-javascript/</guid><description>Static type checking has become an essential aspect of modern JavaScript development, ensuring code reliability, catching errors early, and improving overall code quality.</description><pubDate>Sat, 20 May 2023 11:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;TypeScript and JSDoc are two tools for static type checking in JavaScript.&lt;/li&gt;
&lt;li&gt;TypeScript offers a comprehensive type system, advanced features, and strict type checking.&lt;/li&gt;
&lt;li&gt;JSDoc provides lightweight type annotations and documentation within regular JavaScript comments.&lt;/li&gt;
&lt;li&gt;TypeScript is more suitable for larger projects, while JSDoc can be a lightweight option for basic type checking.&lt;/li&gt;
&lt;li&gt;TypeScript requires a learning curve, a compilation step, and integration challenges.&lt;/li&gt;
&lt;li&gt;JSDoc has limited type checking and lacks advanced language features.&lt;/li&gt;
&lt;li&gt;Consider project size, team familiarity, and integration requirements when choosing between TypeScript and JSDoc for static type checking in JavaScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Static type checking has become an essential aspect of modern JavaScript development, ensuring code reliability, catching errors early, and improving overall code quality. Two popular tools for static type checking in JavaScript are TypeScript and JSDoc. In this article, we will delve into the pros and cons of both TypeScript and JSDoc, exploring their unique features and helping you make an informed decision for your projects.&lt;/p&gt;
&lt;h2&gt;What is TypeScript?&lt;/h2&gt;
&lt;p&gt;TypeScript is a strongly typed superset of JavaScript that introduces static typing to the language. It adds type annotations, interfaces, classes, and other features that enable developers to catch type-related errors during development and compile-time, resulting in more robust and maintainable code. TypeScript&amp;#39;s type system is highly expressive and provides advanced features like union types, intersection types, generics, and more.&lt;/p&gt;
&lt;h2&gt;What is JSDoc?&lt;/h2&gt;
&lt;p&gt;JSDoc, on the other hand, is a documentation syntax for JavaScript that also allows inline type annotations. It helps developers add type information to their code, providing documentation and enabling static analysis by IDEs and other tools. JSDoc uses comments with special tags to describe the types of variables, function parameters, and return values, allowing for some level of static type checking.&lt;/p&gt;
&lt;h2&gt;Comparing TypeScript and JSDoc&lt;/h2&gt;
&lt;p&gt;While both TypeScript and JSDoc offer static type checking capabilities, they differ in several aspects. TypeScript is a language itself, providing a comprehensive type system and compilation process. On the other hand, JSDoc is a documentation syntax that works within JavaScript. TypeScript provides stricter type checking and advanced language features, whereas JSDoc offers a lighter and more flexible approach.&lt;/p&gt;
&lt;h3&gt;Pros of TypeScript&lt;/h3&gt;
&lt;p&gt;TypeScript offers several advantages for static type checking in JavaScript projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improved code maintainability and readability due to explicit type annotations.&lt;/li&gt;
&lt;li&gt;Early detection of type-related errors during the development process.&lt;/li&gt;
&lt;li&gt;Advanced language features like type inference, generics, and modules.&lt;/li&gt;
&lt;li&gt;Enhanced tooling support, including IDE integrations, autocompletion, and refactoring tools.&lt;/li&gt;
&lt;li&gt;Seamless integration with existing JavaScript codebases.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Pros of JSDoc&lt;/h3&gt;
&lt;p&gt;JSDoc, while not as powerful as TypeScript, has its own set of benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lightweight and easy to adopt, as it works within regular JavaScript comments.&lt;/li&gt;
&lt;li&gt;Provides basic type checking and documentation for functions, variables, and objects.&lt;/li&gt;
&lt;li&gt;Compatible with existing JavaScript codebases, without the need for full TypeScript adoption.&lt;/li&gt;
&lt;li&gt;Enables IDEs and other tools to provide autocompletion and static analysis based on type annotations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Cons of TypeScript&lt;/h3&gt;
&lt;p&gt;Despite its strengths, TypeScript has a few limitations that developers should consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learning curve: TypeScript introduces additional syntax and concepts that may require some learning and adjustment for JavaScript developers.&lt;/li&gt;
&lt;li&gt;Compilation step: TypeScript code needs to be compiled to JavaScript before running, adding an extra build step to the development process.&lt;/li&gt;
&lt;li&gt;Integration challenges: Retrofitting TypeScript into existing JavaScript projects can be time-consuming and require significant refactoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Cons of JSDoc&lt;/h3&gt;
&lt;p&gt;Despite its strengths, TypeScript has a few limitations that developers should consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learning curve: TypeScript introduces additional syntax and concepts that may require some learning and adjustment for JavaScript developers.&lt;/li&gt;
&lt;li&gt;Compilation step: TypeScript code needs to be compiled to JavaScript before running, adding an extra build step to the development process.&lt;/li&gt;
&lt;li&gt;Integration challenges: Retrofitting TypeScript into existing JavaScript projects can be time-consuming and require significant refactoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Should I use JSDoc with TypeScript?&lt;/h2&gt;
&lt;p&gt;Considering the limitations of JSDoc and the robustness of TypeScript, it is generally recommended to use TypeScript&amp;#39;s native type system for static type checking. TypeScript provides a more comprehensive and powerful solution, offering better type checking, advanced language features, and seamless integration with JavaScript codebases.&lt;/p&gt;
&lt;h2&gt;Is JSDoc dead?&lt;/h2&gt;
&lt;p&gt;No, JSDoc is not dead. While TypeScript has gained significant popularity in the JavaScript community, JSDoc still serves as a valuable tool for adding basic type annotations and generating documentation. It remains relevant, especially for projects that cannot fully adopt TypeScript or prefer a more lightweight approach to type checking.&lt;/p&gt;
&lt;h2&gt;What can I use instead of JSDoc for TypeScript?&lt;/h2&gt;
&lt;p&gt;If you are using TypeScript, you don&amp;#39;t necessarily need an alternative to JSDoc. TypeScript&amp;#39;s native type system provides comprehensive static type checking capabilities, eliminating the need for additional tools like JSDoc.&lt;/p&gt;
&lt;h2&gt;Should you use Jsdocs?&lt;/h2&gt;
&lt;p&gt;JSDoc can still be beneficial in certain scenarios, such as projects where TypeScript adoption is not feasible or when you require lightweight type annotations and documentation. However, if you are working with TypeScript, utilizing TypeScript&amp;#39;s native type system is generally recommended for a more robust and comprehensive static type checking experience.&lt;/p&gt;
&lt;h2&gt;Choosing the Right Approach&lt;/h2&gt;
&lt;p&gt;When deciding between TypeScript and JSDoc for static type checking, several factors should be considered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Project size and complexity: TypeScript&amp;#39;s stronger type system and advanced features make it well-suited for larger and more complex projects.&lt;/li&gt;
&lt;li&gt;Team familiarity and expertise: If the development team is already proficient in TypeScript or has a strong JavaScript background, TypeScript may be a more natural choice.&lt;/li&gt;
&lt;li&gt;Integration requirements: For existing JavaScript projects or codebases where a full migration to TypeScript is not feasible, JSDoc can be a lightweight option to introduce basic type checking.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ultimately, the choice between TypeScript and JSDoc depends on the specific needs and constraints of your project. Consider the pros and cons discussed here, evaluate your project requirements, and choose the approach that best aligns with your development goals.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Static type checking is a powerful technique for improving code quality and catching errors early in JavaScript development. TypeScript and JSDoc provide different approaches to static type checking, each with its own strengths and weaknesses. While TypeScript offers a comprehensive type system and advanced language features, JSDoc provides a lightweight and flexible option for inline type annotations and documentation. By understanding the pros and cons of TypeScript and JSDoc, you can make an informed decision to ensure effective static type checking in your JavaScript projects.&lt;/p&gt;
&lt;h2&gt;Further Reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/setting-up-node-js-express-mongodb-prettier-eslint-and-husky-application-with-babel-and-authentication-as-an-example&quot;&gt;Setting up Node JS, Express, MongoDB, Prettier, ESLint and Husky Application with Babel and authentication as an example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/setting-up-node-js-express-prettier-eslint-and-husky-application-with-babel-and-typescript-part-1&quot;&gt;Setting up Node JS, Express, Prettier, ESLint and Husky Application with Babel and Typescript: Part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/setting-up-jwt-authentication-in-typescript-with-express-mongodb-babel-prettier-eslint-and-husky-part-2&quot;&gt;Setting up JWT Authentication in Typescript with Express, MongoDB, Babel, Prettier, ESLint, and Husky: Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jsdoc.app/&quot;&gt;JSDoc Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/basic-types.html&quot;&gt;TypeScript Handbook - Basic Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jsdoc.app/about-getting-started.html&quot;&gt;JSDoc - Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html&quot;&gt;Type Checking JavaScript Files - TypeScript Documentation&lt;/a&gt; (Explains how TypeScript can use JSDoc annotations)&lt;/li&gt;
&lt;li&gt;&amp;quot;You Might Not Need TypeScript (or Static Types)&amp;quot; - Eric Elliott. (Provides a counter-argument/alternative perspective.), &lt;a href=&quot;https://medium.com/javascript-scene/you-might-not-need-typescript-or-static-types-aa736c1a3d5&quot;&gt;https://medium.com/javascript-scene/you-might-not-need-typescript-or-static-types-aa736c1a3d5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;TypeScript vs JSDoc for Type Checking in JavaScript&amp;quot; - LogRocket Blog.), [&lt;a href=&quot;https://blog.logrocket.com/typescript-vs-jsdoc-javascript/&quot;&gt;https://blog.logrocket.com/typescript-vs-jsdoc-javascript/&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&amp;quot;When to use JSDoc for type checking&amp;quot; - DEV Community.), &lt;a href=&quot;https://dev.to/samchon/when-to-use-jsdoc-for-type-checking-4j0n&quot;&gt;https://dev.to/samchon/when-to-use-jsdoc-for-type-checking-4j0n&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;JSDoc Reference&amp;quot; - Use JSDoc.), &lt;a href=&quot;https://jsdoc.app/tags-type.html&quot;&gt;https://jsdoc.app/tags-type.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;The Benefits of Static Typing in JavaScript&amp;quot; - SitePoint.), &lt;a href=&quot;https://www.sitepoint.com/benefits-static-typing-javascript/&quot;&gt;https://www.sitepoint.com/benefits-static-typing-javascript/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;TypeScript vs. JavaScript with JSDoc: A Comparative Analysis&amp;quot; - (Example: Search for comparative articles on Medium or other tech blogs.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;Stack Overflow discussions on TypeScript vs. JSDoc.), [Search on Stack Overflow for &amp;quot;TypeScript vs JSDoc&amp;quot;]&lt;/li&gt;
&lt;li&gt;&amp;quot;Why TypeScript is Gaining Popularity&amp;quot; - (Example: Article from a tech news site or developer survey.), [Link to a relevant article]&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>JavaScript</category><category>TypeScript</category><category>Static Typing</category><category>Development Tools</category><category>Code Quality</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0045-typescript-vs-jsdoc-exploring-the-pros-and-cons-of-static-type-checking-in-javascript/hero.jpg" length="0" type="image/jpeg"/></item><item><title>RESTful API vs. GraphQL: Which API is the Right Choice for Your Project?</title><link>https://mkabumattar.com/blog/post/restful-api-vs-graphql-which-api-is-the-right-choice-for-your-project/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/restful-api-vs-graphql-which-api-is-the-right-choice-for-your-project/</guid><description>Consider yourself a software engineer working on a brand-new customer project. Your customer has requested you to develop an application that has to analyze and show a lot of data in real-time. You&apos;ve made the decision to create an API to manage the data, but you&apos;re unsure of the best kind to utilize. Which API should you use the tried-and-true RESTful API or the more recent, customized GraphQL API?</description><pubDate>Sat, 11 Mar 2023 11:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;When deciding between RESTful and GraphQL APIs for a data analysis and display application, it is important to consider the advantages and disadvantages of each. RESTful APIs have been around for a long time and are easy to use and scale, but they can suffer from over-fetching and under-fetching of data, versioning challenges, lack of type safety, and limited querying capabilities. GraphQL APIs offer a lot of flexibility and powerful querying capabilities, but they can be more complex and require more resources to operate. Ultimately, the choice depends on the specific needs of the project.&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Consider yourself a software engineer working on a brand-new customer project. Your customer has requested you to develop an application that has to analyze and show a lot of data in real-time. You&amp;#39;ve made the decision to create an API to manage the data, but you&amp;#39;re unsure of the best kind to utilize. Which API should you use the tried-and-true RESTful API or the more recent, customized GraphQL API?&lt;/p&gt;
&lt;p&gt;It might be difficult to decide between RESTful and GraphQL API, therefore before making a choice, it&amp;#39;s necessary to know each approach&amp;#39;s advantages and disadvantages. Many developers prefer RESTful APIs since they have been around for some time, while GraphQL is a relatively recent addition to the API ecosystem. In this post, we&amp;#39;ll examine both types of APIs&amp;#39; benefits and drawbacks to assist you in selecting the one that will work best for your project.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look at a practical example to better grasp the differences between GraphQL and RESTful. Consider creating a social media program that enables users to publish text updates, videos, and images. To manage the data for the application, you need an API, but you&amp;#39;re not sure which kind to utilize. Do you employ GraphQL or RESTful APIs? To demonstrate the practical distinctions between these two API types, we&amp;#39;ll examine this example in further depth later in the essay.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s crucial to grasp certain fundamental API concepts and tenets before delving into the details of RESTful and GraphQL APIs. It&amp;#39;s also advised to be familiar with web development technologies including HTTP, JSON, and JavaScript.&lt;/p&gt;
&lt;p&gt;A combination of protocols and tools for creating software applications make up an API, or application programming interface. Applications may talk to one another thanks to APIs, allowing various software systems to exchange information and functionality.&lt;/p&gt;
&lt;p&gt;The Hypertext Transfer Protocol, or HTTP, serves as the Web&amp;#39;s data communication&amp;#39;s building block. It&amp;#39;s the protocol that web servers and browsers use to communicate data like HTML pages, pictures, and videos.&lt;/p&gt;
&lt;p&gt;JSON, or JavaScript Object Notation, is a simple data exchange format that is simple for both people and machines to read, write, and understand.&lt;/p&gt;
&lt;p&gt;The computer language JavaScript is used to develop interactive features for web browsers. It is a crucial tool for web development and works with APIs to build responsive and dynamic online apps.&lt;/p&gt;
&lt;p&gt;The advantages and disadvantages of RESTful and GraphQL APIs will be discussed in the following sections, along with practical applications for both technologies in web development.&lt;/p&gt;
&lt;h2&gt;Benefits of RESTful APIs&lt;/h2&gt;
&lt;p&gt;Developers mostly use and like RESTful API, which has been around for a long. Using RESTful APIs has a number of advantages, one of which is its simplicity and use. The RESTful API adheres to a defined set of rules and concepts, making it simple to comprehend and use. Some of the main advantages of RESTful API are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scalability: RESTful APIs are very scalable and have a high request throughput. Each request has all the information required to fulfill it since it is stateless in design. This makes it simple to add new servers to accommodate the increasing traffic and easily grow the API horizontally.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flexibility: RESTful APIs are adaptable and operate with any framework or programming language. Moreover, it works with a variety of gadgets, giving it the perfect option for creating cross-platform apps.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Caching: RESTful APIs offer caching, which may greatly enhance your application&amp;#39;s speed. Caching keeps frequently used data in memory, minimizing the need for server calls and speeding up response times.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simple to troubleshoot: RESTful API is simple to diagnose and debug. It makes it simple to find and fix problems by using standard HTTP status codes to show the status of a request.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s consider our social media application example. Suppose we decide to use RESTful API to handle the data for the application. We can define resources for each data type, such as users, posts, and comments, and use HTTP methods such as GET, POST, PUT, and DELETE to perform actions on these resources. For example, we can use GET to retrieve a user&amp;#39;s profile information or use POST to create a new post. With RESTful API, we can easily build a scalable and flexible API that can handle a large volume of requests from a variety of devices and platforms.&lt;/p&gt;
&lt;h2&gt;Disadvantages of RESTful APIs&lt;/h2&gt;
&lt;p&gt;Although RESTful API offers many advantages, it also has certain disadvantages. The following are some major downsides of utilizing RESTful API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Over-fetching and under-fetching: RESTful API can suffer from over-fetching and under-fetching of data. Over-fetching occurs when the API returns more data than is needed, while under-fetching occurs when the API does not return enough data. This can lead to performance issues and increased network traffic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Versioning: RESTful API requires versioning to ensure backward compatibility. Versioning can lead to complexity and can make it difficult to maintain and update the API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lack of type safety: RESTful API does not provide type safety, which means that errors can occur at runtime if the wrong data type is passed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Limited querying capabilities: RESTful API has limited querying capabilities, making it difficult to retrieve complex data structures or nested data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s consider our social media application example again. Suppose we decide to use RESTful API to handle the data for the application. While RESTful API is a solid choice for building a scalable and flexible API, it can suffer from over-fetching and under-fetching of data. For example, if we retrieve a user&amp;#39;s profile information using RESTful API, we may also receive unnecessary data such as the user&amp;#39;s password or email address. This can lead to increased network traffic and performance issues. Additionally, versioning can be a challenge when using RESTful API, as changes to the API may require updates to the version number.&lt;/p&gt;
&lt;h2&gt;Benefits of GraphQL APIs&lt;/h2&gt;
&lt;p&gt;GraphQL API has many benefits, making it a popular choice for modern applications. Here are some of the key benefits of using GraphQL API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reduced over-fetching and under-fetching: GraphQL API allows for precise querying, which means that the API returns only the data that is requested. This reduces over-fetching and under-fetching of data, leading to improved performance and reduced network traffic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased flexibility: GraphQL API allows for flexible querying and can retrieve complex data structures and nested data with ease. This makes it easier to build and maintain APIs for modern applications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strong typing system: GraphQL API has a strong typing system, which means that type errors can be detected at compile time rather than runtime. This reduces the risk of errors and makes it easier to maintain and update the API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better tooling: GraphQL API has better tooling than RESTful API, making it easier to develop and maintain APIs. For example, GraphQL API has a GraphQL Playground tool that allows developers to test and explore the API.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s consider our social media application example again. Suppose we decide to use GraphQL API to handle the data for the application. With GraphQL API, we can reduce over-fetching and under-fetching of data, ensuring that only the necessary data is returned. This improves performance and reduces network traffic. Additionally, the flexible querying capabilities of GraphQL API make it easier to retrieve complex data structures or nested data, which is important for a social media application. Finally, the strong typing system of GraphQL API reduces the risk of errors and makes it easier to maintain and update the API.&lt;/p&gt;
&lt;h2&gt;Disadvantages of GraphQL APIs&lt;/h2&gt;
&lt;p&gt;While GraphQL API has many benefits, it also has some drawbacks that should be considered. Here are some of the key drawbacks of using GraphQL API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Steep learning curve: GraphQL API has a steep learning curve, especially for developers who are not familiar with it. This can make it challenging to implement and maintain GraphQL APIs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased complexity: GraphQL API can increase the complexity of the API implementation, especially for large applications. This is because it requires careful schema design and implementation to ensure that the API performs well and is easy to use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lack of caching support: GraphQL API does not have built-in caching support, which means that caching must be implemented separately. This can add complexity to the implementation and increase the risk of cache-related issues.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Higher overhead: GraphQL API can have a higher overhead than RESTful API, especially for small applications. This is because it requires additional processing to handle the complex queries and responses.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s consider our social media application example again. If we decide to use GraphQL API to handle the data for the application, we need to be aware of the drawbacks of this API type. For example, the steep learning curve of GraphQL API can make it challenging to implement and maintain. Additionally, the increased complexity of GraphQL API can be a concern for large applications, and the lack of caching support can lead to performance issues. Finally, the higher overhead of GraphQL API can be a concern for small applications, as it may add unnecessary processing time to API requests.&lt;/p&gt;
&lt;h2&gt;Examples of RESTful and GraphQL APIs&lt;/h2&gt;
&lt;h3&gt;RESTful API&lt;/h3&gt;
&lt;p&gt;Social Media Application Example: RESTful API Implementation&lt;/p&gt;
&lt;p&gt;In our social media application, we need to allow users to post photos, videos, and text updates. We also need to allow users to like and comment on posts, follow other users, and view their activity feeds.&lt;/p&gt;
&lt;p&gt;To handle the data for the application, we decide to use RESTful APIs. Here are some of the benefits and disadvantages of this approach:&lt;/p&gt;
&lt;h4&gt;Benefits of RESTful API&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Simple and easy to understand: RESTful API is simple and easy to understand, making it an ideal choice for small to medium-sized applications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Large developer community: RESTful API has a large developer community and is well-documented, which makes it easy to find resources and support.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Caching support: RESTful API has built-in caching support, which can help to improve performance and reduce server load.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalability: RESTful API is scalable, meaning that it can handle large volumes of requests and can be easily scaled up or down as needed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Disadvantages of RESTful API&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Limited flexibility: RESTful API can be limited in terms of flexibility, as it requires predefined endpoints for specific operations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased complexity for larger applications: As the application grows, the complexity of the RESTful API can increase, making it harder to maintain and understand.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Potential for over-fetching and under-fetching: RESTful API can lead to over-fetching or under-fetching of data, which can result in unnecessary data being sent over the network or missing required data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Limited support for real-time updates: RESTful API has limited support for real-time updates, which means that clients must frequently poll the server for updates.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In summary, using RESTful API can provide a simple and scalable solution for our social media application. However, as the application grows, we need to be aware of the potential drawbacks, such as limited flexibility and increased complexity.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s explore how our social media application would look if we decided to use GraphQL API instead.&lt;/p&gt;
&lt;h3&gt;GraphQL API&lt;/h3&gt;
&lt;p&gt;Example: Social Media Application Using GraphQL APIs&lt;/p&gt;
&lt;h4&gt;Benefits of GraphQL API&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Increased efficiency: With GraphQL, the server only sends back the data requested by the client, which reduces the amount of unnecessary data transferred over the network. This can significantly improve the performance of your application, especially when dealing with large amounts of data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flexible queries: GraphQL allows clients to specify exactly what data they need and how it should be structured. This means that clients can request different data structures from the same endpoint, making it easier to support different types of clients (e.g. web, mobile, etc.).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strong typing: GraphQL has a built-in type system, which makes it easier to validate client requests and prevent runtime errors. This can help to catch errors early in the development process, and make it easier to maintain your API over time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Disadvantages of GraphQL API&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Learning curve: GraphQL has a steeper learning curve than RESTful APIs, especially if you&amp;#39;re not familiar with the concept of a graph data model. This can make it more difficult for developers who are new to GraphQL to get started with it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Caching challenges: Because GraphQL allows clients to request different data structures from the same endpoint, caching can be more challenging than with RESTful APIs. This can lead to more complex caching strategies and potentially slower performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server complexity: GraphQL APIs can be more complex to implement on the server side, especially if you&amp;#39;re dealing with complex data structures or relationships. This can require more advanced programming skills and potentially more development time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, GraphQL can be a powerful tool for building efficient and flexible APIs, especially for applications that need to support different types of clients or deal with large amounts of data. However, it does come with some tradeoffs and requires a different approach than RESTful APIs.&lt;/p&gt;
&lt;p&gt;In conclusion, choosing between RESTful and GraphQL APIs depends on the specific needs and constraints of your application. Both APIs have their strengths and weaknesses, and the decision ultimately comes down to what makes the most sense for your particular use case.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In conclusion, the choice between RESTful and GraphQL API depends on various factors such as the complexity of the application, the type of data to be exchanged, and the development team&amp;#39;s preference.&lt;/p&gt;
&lt;p&gt;Finding resources and assistance for RESTful API is simple due to its widespread use and well-established reputation. Also, it adheres to a stateless design, which makes scaling and caching simpler. For complicated data queries, it might not be the best approach because it might lead to data over- or under-fetching. The GraphQL API, on the other hand, offers greater flexibility in data searching and lets customers specify the precise data they need. Moreover, it lessens the requirement for several API endpoints and boosts efficiency by lowering network overhead. It may not be appropriate for basic data models and needs more work to set up and administer.&lt;/p&gt;
&lt;p&gt;The choice between a GraphQL API and a RESTful API ultimately comes down to the project&amp;#39;s particular needs and objectives. When choosing a course of action, developers should thoroughly weigh the advantages and disadvantages of each strategy.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;GraphQL Official Website.), &lt;a href=&quot;https://graphql.org/&quot;&gt;https://graphql.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Introduction to REST APIs&amp;quot; - Red Hat.), &lt;a href=&quot;https://www.redhat.com/en/topics/api/what-is-a-rest-api&quot;&gt;https://www.redhat.com/en/topics/api/what-is-a-rest-api&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fielding, Roy T. &amp;quot;Architectural Styles and the Design of Network-based Software Architectures.&amp;quot; (Chapter 5 discusses REST.), &lt;a href=&quot;https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm&quot;&gt;https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;GraphQL vs. REST: A Deep Dive into Two API Paradigms&amp;quot; - Apollo GraphQL Blog.), &lt;a href=&quot;https://www.apollographql.com/blog/graphql-vs-rest-5d425123e34b/&quot;&gt;https://www.apollographql.com/blog/graphql-vs-rest-5d425123e34b/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;RESTful Web Services&amp;quot; - Wikipedia.), &lt;a href=&quot;https://en.wikipedia.org/wiki/Representational_state_transfer&quot;&gt;https://en.wikipedia.org/wiki/Representational_state_transfer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;GraphQL: The Documentary&amp;quot; - YouTube.), &lt;a href=&quot;https://www.youtube.com/watch?v=783ccP__No8&quot;&gt;https://www.youtube.com/watch?v=783ccP__No8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Understanding REST vs GraphQL&amp;quot; - Smashing Magazine.), &lt;a href=&quot;https://www.smashingmagazine.com/2020/01/understanding-rest-graphql/&quot;&gt;https://www.smashingmagazine.com/2020/01/understanding-rest-graphql/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;API Design Best Practices&amp;quot; - Swagger/OpenAPI. (Relevant for REST API design.), &lt;a href=&quot;https://swagger.io/resources/articles/best-practices-in-api-design/&quot;&gt;https://swagger.io/resources/articles/best-practices-in-api-design/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;GraphQL Best Practices&amp;quot; - GraphQL Official Documentation.), &lt;a href=&quot;https://graphql.org/learn/best-practices/&quot;&gt;https://graphql.org/learn/best-practices/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Over-fetching and Under-fetching in APIs&amp;quot; - (Example: Search for articles explaining this concept in detail.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Caching in REST vs. GraphQL&amp;quot; - (Example: Article from a tech blog like LogRocket or Netlify.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;When to Use GraphQL vs. REST&amp;quot; - Auth0 Blog.), &lt;a href=&quot;https://auth0.com/blog/when-to-use-graphql-vs-rest/&quot;&gt;https://auth0.com/blog/when-to-use-graphql-vs-rest/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;HTTP Status Codes&amp;quot; - MDN Web Docs. (Relevant for REST APIs.), &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;GraphQL Schema Definition Language (SDL)&amp;quot; - GraphQL Official Documentation.), &lt;a href=&quot;https://graphql.org/learn/schema/&quot;&gt;https://graphql.org/learn/schema/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>API Design</category><category>Web Development</category><category>Backend Architecture</category><category>Software Engineering</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0044-restful-api-vs-graphql-which-api-is-the-right-choice-for-your-project/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Mastering AWS Architecture: A Comprehensive Guide to the Well-Architected Framework</title><link>https://mkabumattar.com/blog/post/mastering-aws-architecture-a-comprehensive-guide-to-the-well-architected-framework/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/mastering-aws-architecture-a-comprehensive-guide-to-the-well-architected-framework/</guid><description>This article provides an overview of the AWS Well-Architected Framework, a set of best practices for designing and operating reliable, efficient, secure, and sustainable systems on AWS. The framework consists of five pillars: Operational Excellence, Security, Reliability, Performance Efficiency, and Cost Optimization, with Sustainability being the sixth pillar. The article explores each pillar and explains how organizations can apply the framework to optimize their AWS infrastructure. It also provides examples of how AWS services can be used to improve the efficiency, security, reliability, cost-effectiveness, and sustainability of cloud systems.</description><pubDate>Thu, 09 Mar 2023 11:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;AWS Well-Architected Framework is a collection of best practices for creating and running systems on AWS that are dependable, secure, effective, economical, and long-lasting. The framework is built around five pillars: operational excellence, security, reliability, performance efficiency, and cost optimization. A sixth pillar, sustainability, is also included and is dedicated to reducing the environmental effect of systems and advancing sustainable business practices. Organizations may optimize their cloud infrastructure, save costs, boost performance, and help create a more sustainable future by heeding the recommendations of the AWS Well-Architected Framework.&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Imagine that you have created a stunning new home that was meticulously designed and built to match your specific needs. Yet as time passes, you begin to see some foundation cracks, roof leaks, and other problems that lower the standard of your house as a whole. These difficulties are comparable to those that businesses using cloud computing services like AWS Web Services have (AWS). While there are numerous advantages to using AWS, businesses might encounter issues that compromise the dependability, security, and cost-effectiveness of their cloud infrastructure without careful planning and execution.&lt;/p&gt;
&lt;p&gt;The AWS Well-Architected Framework enters the picture here. The framework offers a collection of best practices and principles for creating and managing efficient, effective, and reasonably priced systems in the AWS cloud. Organizations can make sure that their cloud infrastructure is tailored to their unique requirements and that they are getting the most out of utilizing AWS by adhering to the framework.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s use the example of a business wanting to launch a new web application on AWS. They may make sure the application is created to be highly available, safe, and economical by utilizing the AWS Well-Architected framework. To make sure the application can cope with variable amounts of traffic without going offline, they can leverage AWS services like Elastic Load Balancing and Auto Scaling. Companies may also put security best practices into reality, such as employing AWS Identity and Access Management (IAM) to restrict access to resources and routinely evaluating their infrastructure for flaws.&lt;/p&gt;
&lt;p&gt;Overall, the AWS Well-Architected framework is a useful tool for any business adopting AWS, assisting them in avoiding common errors and guaranteeing that their cloud architecture is tailored to their particular requirements.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s crucial to comprehend the prerequisites necessary to use the AWS Well-Architected framework efficiently before delving in. Let&amp;#39;s look at a practical example to show how important these requirements are.&lt;/p&gt;
&lt;p&gt;Consider a business that wishes to transfer its current IT infrastructure to AWS. They want to profit from the advantages of using the cloud, such as its greater scalability and flexibility, and they have heard about these advantages. They rapidly learn, though, that their present infrastructure was not created with the cloud in mind. Their staff is underprepared to use AWS services successfully, and they have outdated apps that don&amp;#39;t perform well in the cloud.&lt;/p&gt;
&lt;p&gt;This emphasizes how crucial it is to set up specific prerequisites before attempting to use the AWS Well-Architected framework. These conditions include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Knowledge of cloud computing: It&amp;#39;s critical to have a solid grasp of cloud computing principles and services, as well as the advantages and disadvantages of using the cloud. With instruction, certification, and practical experience with AWS services, one can acquire this expertise.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Business goals: It&amp;#39;s essential to understand the goals that the AWS infrastructure is designed to help you achieve. This involves choosing success measures and key performance indicators (KPIs).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Technical requirements: It&amp;#39;s crucial to determine the system&amp;#39;s technical requirements, such as scalability, security, and availability, before constructing an AWS architecture. This will make it more likely that the infrastructure will be created with the organization&amp;#39;s requirements in mind.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plan for migration: Whenever moving current systems to AWS, it&amp;#39;s crucial to have a thorough plan outlining the procedure, including the services and tools that will be utilized, the sequence in which they will be migrated, and the anticipated timeframe.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s take the scenario where a business wishes to move its current website to AWS. They must make sure they have the technical know-how to create a secure architecture that can handle the traffic on the website. Their business goals and KPIs, such as website uptime and response speed, must also be clearly understood. They must also have a migration strategy in place that involves moving their website to the cloud utilizing AWS services like AWS Server Migration Service.&lt;/p&gt;
&lt;p&gt;Organizations may successfully design and build a cloud infrastructure that satisfies their goals and optimizes the advantages of utilizing AWS by making sure that these conditions are met before adopting the AWS Well-Architected framework.&lt;/p&gt;
&lt;h2&gt;What is the AWS Well-Architected Framework?&lt;/h2&gt;
&lt;p&gt;After discussing the requirements for successfully utilizing the AWS Well-Architected framework, let&amp;#39;s get into what the framework is.&lt;/p&gt;
&lt;p&gt;For creating and running dependable, secure, effective, and reasonably priced systems on the AWS cloud, a set of best practices and principles known as the AWS Well-Architected framework is available. The methodology is meant to assist businesses in assessing current cloud infrastructures and pinpointing possible areas for development. Organizations may compare their design to industry best practices by using it as a standardized method of assessing cloud architectures across various sectors and use cases.&lt;/p&gt;
&lt;p&gt;The AWS Well-Architected framework consists of six pillars:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Operational Excellence: Focuses on the ability to run and monitor systems to deliver business value and to continually improve supporting processes and procedures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security: Focuses on protecting information and systems. This includes identifying and mitigating potential security threats and vulnerabilities.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reliability: Focuses on ensuring that systems operate correctly and consistently and that they can recover from failures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance Efficiency: Focuses on using computing resources efficiently to meet system requirements and maintain performance as demand changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost Optimization: Focuses on avoiding unnecessary costs and maximizing the value of cloud investments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sustainability: This pillar focuses on designing systems that are environmentally sustainable and reduce the carbon footprint of IT infrastructure.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consider a scenario in which a business has developed a new application on AWS that is having performance problems. The Performance Efficiency pillar of their design may be assessed using the AWS Well-Architected methodology. Companies may discover that they are not efficiently leveraging AWS services like AWS CloudFront or AWS Elastic Load Balancing, which causes their users&amp;#39; response times to be delayed. They may enhance the application&amp;#39;s performance and give users a better experience by putting best practices from the Performance Efficiency pillar into effect, such as improving data transmission across AWS services.&lt;/p&gt;
&lt;p&gt;The AWS Well-Architected architecture, in general, offers businesses a disciplined method for planning and managing their cloud infrastructure on AWS. Organizations may use the framework to make sure their systems are dependable, secure, effective, and economical, and that they are getting the most out of utilizing AWS.&lt;/p&gt;
&lt;h2&gt;Operational Excellence&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s discuss Operational Excellence, the first pillar of the AWS Well-Architected methodology, in more detail.&lt;/p&gt;
&lt;p&gt;Operational Excellence is all about ensuring systems run effectively and efficiently, delivering business value while continually improving supporting processes and procedures. This involves developing and implementing standard operating procedures, monitoring systems, and establishing metrics to measure success.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s say a company is running a website on AWS that is experiencing intermittent downtime, leading to frustrated users and lost revenue. Using the Operational Excellence pillar of the AWS Well-Architected framework, they can identify ways to improve their system uptime and minimize disruptions.&lt;/p&gt;
&lt;p&gt;Using Amazon&amp;#39;s managed services, which may automate many of the chores related to running and monitoring systems, is one method for enhancing operational excellence on AWS. For instance, the business may set up alerts that alert them when their website is experiencing unavailability using Amazon CloudWatch, a managed service that offers monitoring and operational insights for AWS resources. They will be able to swiftly detect and fix problems before they affect users thanks to this.&lt;/p&gt;
&lt;p&gt;In addition, the company can establish a continuous improvement process to ensure that its website remains stable and reliable over time. This may involve setting up regular reviews of system performance and making incremental improvements to optimize system efficiency and reduce downtime.&lt;/p&gt;
&lt;p&gt;Overall, the Amazon Well-Architected framework&amp;#39;s Operational Excellence pillar offers a collection of best practices for creating and running dependable, scalable, and effective systems. Organizations may reduce downtime, enhance system performance, and provide value to their clients by using these practices.&lt;/p&gt;
&lt;h2&gt;Security&lt;/h2&gt;
&lt;p&gt;Security is the second pillar of the Amazon Well-Architected Framework. One of the most important components of any IT infrastructure is security, which is necessary to defend against online attacks and safeguard sensitive data, systems, and applications.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s imagine that a business uses AWS to store and handle sensitive customer data, including financial or personal identification data. The business is responsible for making sure the data is safe and shielded from harmful activity and illegal access. The business is able to identify and put into effect best practices for protecting its data and systems by utilizing the Security pillar of the AWS Well-Architected Framework.&lt;/p&gt;
&lt;p&gt;The Security pillar includes a set of best practices for securing AWS resources and applications, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Identity and Access Management (IAM): This pillar&amp;#39;s main goal is to guarantee that only authorized users may access AWS resources and that access is allowed in accordance with the least-privilege principle.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Detection and Response: This pillar concentrates on promptly identifying and counteracting security risks to lessen the effects of security events.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Infrastructure Protection: Implementing firewalls, intrusion detection systems, and encryption are only a few of the measures included in this pillar&amp;#39;s protection of infrastructure against internal and external threats.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data Protection: Encryption, key management, data backup, and recovery are all aspects of this pillar&amp;#39;s protection of data both in transit and at rest.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To manage access to Amazon resources, the business may, for instance, utilize AWS Identity and Access Management (IAM). The danger of unwanted access or unintentional data disclosure is decreased since the business may utilize IAM to provide each person or application the bare minimal set of permissions required to carry out their job.&lt;/p&gt;
&lt;p&gt;Overall, the Amazon Well-Architected Framework&amp;#39;s Security pillar offers a collection of best practices for protecting AWS resources and applications. Organizations may lower the risk of security lapses and safeguard sensitive data and systems from online attacks by putting these best practices into effect.&lt;/p&gt;
&lt;h2&gt;Reliability&lt;/h2&gt;
&lt;p&gt;Reliability is the third pillar of the AWS Well-Architected Framework. The main goal of reliability is to make sure that systems function normally with little disturbance or downtime. This is particularly crucial for mission-critical applications that have to be accessible nonstop and throughout the clock.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look at an example of an e-commerce business that uses AWS to power its website. The business must make sure that its website is responsive and constantly available, especially during busy times like the Christmas shopping season. The business is able to identify and put into practice best practices for guaranteeing high availability and uptime by using the Reliability pillar of the AWS Well-Architected Framework.&lt;/p&gt;
&lt;p&gt;The Reliability Pillar includes a set of best practices for designing and operating resilient systems, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Foundations: This pillar focuses on establishing a solid foundation for systems, including the use of fault-tolerant hardware and software, redundancy, and automatic scaling.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Failure Management: This pillar focuses on managing failures when they occur, including planning for failures, monitoring for failures, and implementing automatic recovery procedures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change Management: This pillar focuses on managing changes to systems and applications, including testing, validating, and documenting changes before implementing them.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, the company may use AWS Elastic Load Balancing (ELB) and Amazon EC2 Auto Scaling to ensure that its website is always accessible, even during periods of high traffic. ELB intelligently distributes incoming traffic among many Amazon EC2 instances, avoiding any one instance from getting overburdened. The website can endure traffic surges without going offline because to Amazon EC2 Auto Scaling, which automatically adjusts the number of EC2 instances based on traffic demand.&lt;/p&gt;
&lt;p&gt;In addition, the company can use AWS CloudFormation to automate the deployment of infrastructure and applications, ensuring that changes are tested and validated before being implemented. CloudFormation templates can be version-controlled and reviewed, providing a structured process for managing changes to systems and applications.&lt;/p&gt;
&lt;p&gt;Overall, the Amazon Well-Architected Framework&amp;#39;s Reliability pillar offers a collection of best practices for creating and running highly available and resilient systems. Organizations may make sure that their systems function as planned with little interruption and downtime by putting these best practices into effect.&lt;/p&gt;
&lt;h2&gt;Performance Efficiency&lt;/h2&gt;
&lt;p&gt;The fourth pillar of the AWS Well-Architected framework is Performance Efficiency. This pillar focuses on using computing resources efficiently and effectively, to achieve desired outcomes and maximize the return on investment.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s consider an example of a media company using AWS to host their streaming platform. The company needs to ensure that its platform can deliver high-quality video streaming to users, while also optimizing costs and minimizing resource waste. By using the Performance Efficiency pillar of the AWS Well-Architected framework, the company can identify and implement best practices for achieving these goals.&lt;/p&gt;
&lt;p&gt;The Performance Efficiency pillar includes a set of best practices for designing and operating high-performance systems, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Selection: This pillar focuses on selecting the right computing, storage, and database services to meet the specific needs of the workload, based on performance, cost, and other factors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Review: This pillar focuses on reviewing systems regularly to ensure that they are using resources efficiently, and identifying opportunities for optimization.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monitoring: This pillar focuses on monitoring systems to identify performance issues and bottlenecks, and using data to inform optimization decisions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, the media organization can utilize Amazon CloudFront and Amazon S3 to enhance the transmission of its video content. A content delivery network (CDN) called CloudFront delivers material globally to enhance performance and lower latency. S3 is a highly scalable and reliable storage service that can store and retrieve any volume of data from any location on the internet.&lt;/p&gt;
&lt;p&gt;By using CloudFront, the media company can deliver their video content from edge locations that are closer to the end-users, reducing latency and improving performance. They can also use CloudFront to cache frequently accessed content, reducing the load on their origin servers and optimizing costs. By using S3, the company can store and retrieve its video content reliably and cost-effectively, with high durability and availability.&lt;/p&gt;
&lt;p&gt;Also, the business may utilize Amazon CloudWatch to keep tabs on the efficiency of its systems and spot areas for improvement. Amazon resources are monitored and recorded in real-time by CloudWatch, which may also be used to create alarms and start automatic processes depending on performance data.&lt;/p&gt;
&lt;p&gt;Overall, the AWS Well-Architected framework&amp;#39;s Performance Efficiency pillar offers a collection of best practices for creating and running systems that are effective, efficient, and cost-efficient. Organizations may accomplish their targeted results while optimizing return on investment by putting these best practices into effect.&lt;/p&gt;
&lt;h2&gt;Cost Optimization&lt;/h2&gt;
&lt;p&gt;Certainly! Let&amp;#39;s discuss the Cost Optimization pillar of the AWS Well-Architected framework.&lt;/p&gt;
&lt;p&gt;Imagine a company that is running a large-scale application on AWS. The company is experiencing unexpectedly high costs, and they&amp;#39;re struggling to identify ways to optimize its spending. By using the Cost Optimization pillar of the AWS Well-Architected framework, they can identify areas where they can reduce costs while still meeting their performance and scalability requirements.&lt;/p&gt;
&lt;p&gt;The Cost Optimization pillar includes a set of best practices for optimizing costs and maximizing the value of your AWS infrastructure, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cost-Aware Architecture: This pillar focuses on designing and deploying systems that are cost-efficient and scalable, using services that are optimized for cost-effectiveness.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost-Effective Resources: This pillar focuses on using the most cost-effective AWS resources for your application, such as using reserved instances instead of on-demand instances.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Matching Supply and Demand: This pillar focuses on optimizing resource allocation and usage to match demand, using tools like Auto Scaling to automatically adjust resources based on usage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optimizing Over Time: This pillar focuses on continuously reviewing and optimizing your AWS infrastructure over time, using tools like AWS Cost Explorer to identify cost-saving opportunities.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, suppose the business runs its application on Amazon EC2 instances. With AWS&amp;#39;s Spot Instances, which enable them to bid on unutilized EC2 capacity at a cheaper price than on-demand instances, they may reduce expenditures. This can provide the requisite performance and scalability at a substantial cost savings.&lt;/p&gt;
&lt;p&gt;Also, the business may utilize Amazon Cost Explorer to examine its consumption and find areas where costs might be reduced. To cut expenses, businesses could decide to terminate or downsize instances that are operating at low usage rates, for instance.&lt;/p&gt;
&lt;p&gt;Overall, the AWS Well-Architected framework&amp;#39;s Cost Optimization pillar offers a collection of best practices for cutting expenses and enhancing the use of your AWS infrastructure. Organizations may cut expenses while still achieving their performance and scalability goals by implementing these techniques.&lt;/p&gt;
&lt;h2&gt;Sustainability&lt;/h2&gt;
&lt;p&gt;Certainly, let&amp;#39;s talk about the Sustainability pillar of the AWS Well-Architected framework. This pillar focuses on designing and operating systems that minimize their environmental impact and promote sustainable business practices.&lt;/p&gt;
&lt;p&gt;For example, the business may employ AWS&amp;#39;s services to increase the web application&amp;#39;s energy efficiency. Using AWS&amp;#39;s Auto Scaling function, which automatically modifies the number of instances operating in response to variations in demand, might be one strategy. The firm may avoid running surplus infrastructure by dynamically altering its capacity, which lowers energy use and emissions.&lt;/p&gt;
&lt;p&gt;Additionally, the company can use AWS&amp;#39;s Carbon Footprint tool to measure and report its environmental impact. This tool calculates the carbon emissions associated with running AWS resources, allowing the company to identify areas for improvement and track progress over time.&lt;/p&gt;
&lt;p&gt;Overall, the AWS Well-Architected framework&amp;#39;s Sustainability pillar offers a set of best practices for developing and running systems that support sustainable business operations. Organizations may reduce their environmental effect and help to create a more sustainable future by putting these ideas into practice.&lt;/p&gt;
&lt;h2&gt;Applying the AWS Well-Architected Framework&lt;/h2&gt;
&lt;p&gt;Consider a business that wants to move its IT infrastructure to Amazon to benefit from the scalability, flexibility, and affordability of the cloud. They are worried about how to construct its architecture, though, to make sure it is dependable, secure, economical, and long-lasting.&lt;/p&gt;
&lt;p&gt;The business may utilize the Amazon Well-Architected Framework, a set of best practices and principles for developing and running dependable, effective, and secure cloud-based systems, to allay these worries. The operational excellence, security, reliability, performance effectiveness, and cost optimization pillars make up the Amazon Well-Architected Framework.&lt;/p&gt;
&lt;p&gt;To apply the AWS Well-Architected Framework, the company can work with AWS experts or partners to conduct a Well-Architected Review, which is a process of evaluating the current state of their architecture against the five pillars of the framework. This review can help identify areas of improvement, prioritize actions, and provide recommendations for optimizing the architecture to better align with AWS best practices.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s say the company undergoes a Well-Architected Review and identifies that its infrastructure is not cost-optimized and that they are spending more than necessary on its cloud resources. The AWS expert conducting the review may suggest implementing AWS services such as AWS Cost Explorer, which provides visibility into the company&amp;#39;s AWS spending and enables them to analyze and optimize their costs.&lt;/p&gt;
&lt;p&gt;In addition, by implementing the Amazon Well-Architected Framework, the business may lessen the chance of downtime and security breaches by identifying possible issues before they become problems. The organization may enhance the overall health and performance of its infrastructure by putting the best practices recommended in the framework into practice, which will lower the chance of problems that could have an adverse effect on its clients and business operations.&lt;/p&gt;
&lt;p&gt;After the Well-Architected Review, the company can prioritize the recommended actions and start implementing the changes necessary to optimize its infrastructure. The company can continue to use the AWS Well-Architected Framework as a guide to maintain the health and performance of its infrastructure over time, adapting to changes in business needs and technological advancements.&lt;/p&gt;
&lt;p&gt;Overall, implementing the Amazon Well-Architected Framework offers a systematic and thorough approach to developing and running cloud infrastructure that satisfies business goals, is compliant with AWS best practices, and enhances efficiency, security, dependability, and cost-effectiveness.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In conclusion, the Amazon Well-Architected Framework is a set of best practices created to aid businesses in developing and managing dependable, secure, productive, and affordable systems on AWS. By utilizing the framework, businesses may steer clear of typical mistakes, cut expenses, and improve the performance and dependability of their systems. The framework offers a structured method for developing and assessing systems, spotting possible problems, and putting corrective measures in place.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;AWS Well-Architected Framework - Main Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://d1.awsstatic.com/whitepapers/architecture/AWS_Well-Architected_Framework.pdf&quot;&gt;AWS Well-Architected Framework Whitepaper (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/operational-excellence-pillar/welcome.html&quot;&gt;Operational Excellence Pillar Whitepaper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/welcome.html&quot;&gt;Security Pillar Whitepaper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/welcome.html&quot;&gt;Reliability Pillar Whitepaper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/performance-efficiency-pillar/welcome.html&quot;&gt;Performance Efficiency Pillar Whitepaper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/cost-optimization-pillar/welcome.html&quot;&gt;Cost Optimization Pillar Whitepaper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/sustainability-pillar/welcome.html&quot;&gt;Sustainability Pillar Whitepaper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/well-architected-tool/&quot;&gt;AWS Well-Architected Tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wellarchitectedlabs.com/&quot;&gt;AWS Well-Architected Labs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/professional-services/CAF/&quot;&gt;AWS Cloud Adoption Framework (CAF)&lt;/a&gt; (Related framework for cloud adoption)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/architecture/&quot;&gt;AWS Architecture Center&lt;/a&gt; (Provides reference architectures and guidance)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/aws-cost-management/aws-cost-explorer/&quot;&gt;AWS Cost Explorer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/iam/&quot;&gt;AWS Identity and Access Management (IAM)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/cloudwatch/&quot;&gt;Amazon CloudWatch&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AWS</category><category>Cloud Architecture</category><category>Best Practices</category><category>DevOps</category><category>Cloud Management</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0043-mastering-aws-architecture-a-comprehensive-guide-to-the-well-architected-framework/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Get Started with Building ReactJS and Docker: A Complete Guide</title><link>https://mkabumattar.com/blog/post/get-started-with-building-reactjs-and-docker-a-complete-guide/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/get-started-with-building-reactjs-and-docker-a-complete-guide/</guid><description>This article is a complete guide for building and deploying a React JS application with Docker, including prerequisites, environment setup, building, containerizing, deployment, and best practices. It also includes an example of running a React JS application with Docker Compose.</description><pubDate>Sat, 18 Feb 2023 11:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Docker is a powerful tool that allows developers to create, deploy, and run applications in a portable and scalable way. It uses containerization to encapsulate all the dependencies and configurations required for an application, ensuring it runs consistently and predictably on any system.&lt;/p&gt;
&lt;p&gt;React JS, on the other hand, is a JavaScript library for building user interfaces. It provides a powerful and efficient way to create dynamic, responsive, and interactive applications. React JS is an essential tool for modern web development, and it&amp;#39;s used by many companies worldwide.&lt;/p&gt;
&lt;p&gt;In this guide, we&amp;#39;ll explore how to use Docker to build, run, and deploy a React JS application. We&amp;#39;ll start by setting up our environment and installing Docker, and then move on to creating a Dockerfile to build our application. We&amp;#39;ll also learn how to containerize the application and deploy it to a production environment using Docker.&lt;/p&gt;
&lt;p&gt;By the end of this guide, you&amp;#39;ll have a solid understanding of how to use Docker to manage a React JS application, making it easier to develop, deploy, and maintain.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before getting started with building React JS and Docker, there are a few prerequisites you need to have in place.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Basic Knowledge of React JS&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To follow along with this guide, you should have a basic understanding of React JS. If you&amp;#39;re new to React, we recommend completing a beginner-level course to get familiar with the library. Or you can follow our &lt;a href=&quot;/blog/post/building-a-customizable-image-slider-in-react-using-hooks-scss-and-typescript&quot;&gt;Building a Customizable Image Slider in React Using Hooks, SCSS, and TypeScript&lt;/a&gt; guide to learn how to build a React JS application from scratch.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;A Code Editor&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You&amp;#39;ll need a code editor to create and edit the React JS application files. There are many options available, such as Visual Studio Code, Sublime Text, and Atom. &lt;a href=&quot;/cheatsheets/vscode&quot;&gt;Visual Studio Code Cheatsheet&lt;/a&gt; is a great resource to get started with Visual Studio Code.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Docker Installed on Your System&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To use Docker, you&amp;#39;ll need to have it installed on your system. Docker is compatible with most operating systems, including Windows, macOS, and Linux. You can follow our previous article on installing Docker for Linux distros to get started. Or you can follow the &lt;a href=&quot;/blog/post/how-to-install-docker-on-linux-in-4-easy-steps&quot;&gt;How To Install Docker On Linux In 4 Easy Steps!&lt;/a&gt; guide to install Docker on Linux.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;A Terminal or Command Prompt&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Docker is primarily used through the command line interface (CLI). Therefore, you&amp;#39;ll need a terminal or command prompt to execute Docker commands. If you&amp;#39;re using Windows, you can use PowerShell or Command Prompt. For macOS and Linux, you can use the built-in terminal.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;A Github Account (Optional)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To share your React JS and Docker project with the community, you can use Github to host your code. Github is a popular platform for hosting open-source projects, and it provides a simple way to collaborate with others.&lt;/p&gt;
&lt;p&gt;By ensuring you have these prerequisites in place, you&amp;#39;ll be well-prepared to follow along with this guide and start building your React JS application with Docker.&lt;/p&gt;
&lt;h2&gt;Preparing Your Environment for Docker&lt;/h2&gt;
&lt;p&gt;To start building a React JS application with Docker, you need to prepare your environment. This involves ensuring your system meets Docker&amp;#39;s requirements, installing Docker on your operating system, and configuring Docker to work with React JS.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;System Requirements&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before installing Docker, you need to make sure your system meets its requirements. Docker requires a 64-bit version of your operating system and a processor with virtualization support. It&amp;#39;s also recommended to have at least 4GB of RAM and 20GB of disk space.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Installing Docker&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you&amp;#39;ve verified your system meets the requirements, you can install Docker. Docker provides installation guides for most operating systems on their website. You can follow the guide for your operating system to get started.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Configuring Docker for React JS&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After installing Docker, you need to configure it to work with React JS. You can do this by creating a Dockerfile, which is a configuration file that defines the environment and settings for your application. You can use a pre-built Docker image that includes Node.js, the runtime environment for React JS, or you can build your own Docker image.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Using a Pre-Built Docker Image&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you prefer to use a pre-built Docker image, you can use the official Node.js image provided by Docker. This image includes Node.js and other necessary dependencies for running React JS. You can specify the Node.js version in the Dockerfile to ensure your application runs on the desired version.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Building Your Own Docker Image&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you want more control over the environment and dependencies for your React JS application, you can build your own Docker image. You can start with a base image, such as the official Node.js image, and add the necessary dependencies and configurations for your application.&lt;/p&gt;
&lt;p&gt;By preparing your environment for Docker, you&amp;#39;ll be able to create a stable and efficient environment for building, running, and deploying your React JS application.&lt;/p&gt;
&lt;h2&gt;Building a React JS Application with Docker&lt;/h2&gt;
&lt;p&gt;Now that we have our environment prepared, we can start building our React JS application with Docker. In this section, we&amp;#39;ll walk through the steps for building a React JS application using a Dockerfile and containerizing the application.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating a Dockerfile&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first step in building our application with Docker is to create a Dockerfile. The Dockerfile defines the environment and settings for our application. We can use a pre-built Node.js image, as we mentioned earlier, or we can build our own image. In our case, we&amp;#39;ll use the official Node.js image.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of a Dockerfile for a React JS application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Use an official Node.js runtime as a parent image
FROM node:18.14.0

# Set the working directory
WORKDIR /app

# Set the environment variables
EXPOSE 3030

# Copy the package.json and package-lock.json files to the working directory
COPY package*.json ./

# Install dependencies
RUN npm install

# Install serve globally
RUN npm install serve -g

# Copy the remaining application files to the working directory
COPY . .

# Build the application
RUN npm run build

# Set the command to dev the application
CMD [ &amp;quot;npm&amp;quot;, &amp;quot;run&amp;quot;, &amp;quot;serve&amp;quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This Dockerfile uses the Node.js 18 image as a parent image, sets the working directory, copies the necessary files, installs dependencies, builds the application, and sets the command to start the application.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Building the Docker Image&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once we have our Dockerfile, we can build the Docker image by running the following command in the terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker build -t react-slider .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0042-get-started-with-building-reactjs-and-docker-a-complete-guide/building-the-docker-image.png&quot; alt=&quot;Building the Docker Image&quot;&gt;&lt;/p&gt;
&lt;p&gt;This command builds the Docker image using the Dockerfile in the current directory and tags it with the name &lt;code&gt;react-slider&lt;/code&gt;. The period at the end specifies that the build context is the current directory.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Running the Docker Container&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After building the Docker image, we can run the Docker container using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run -p 3030:3030 -d react-slider
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command starts a new Docker container and maps port &lt;code&gt;3030&lt;/code&gt; of the container to port &lt;code&gt;3030&lt;/code&gt; of the host system. The &lt;code&gt;react-slider&lt;/code&gt; argument specifies the name of the Docker image we want to use.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Accessing the React JS Application&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the Docker container is running, we can access the React JS application in the browser by navigating to &lt;code&gt;http://localhost:3030&lt;/code&gt;. This is the default port for React JS applications, and we specified it in the Dockerfile.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0042-get-started-with-building-reactjs-and-docker-a-complete-guide/accessing-the-react-js-application.png&quot; alt=&quot;Accessing the React JS Application&quot;&gt;&lt;/p&gt;
&lt;p&gt;By following these steps, we&amp;#39;ve successfully built a React JS application with Docker, making it easy to develop, run, and deploy the application in a consistent and scalable way.&lt;/p&gt;
&lt;h2&gt;Running a React JS Application with Docker Composer&lt;/h2&gt;
&lt;p&gt;In this section, we&amp;#39;ll explore how to run a React JS application with Docker Composer. Docker Composer is a tool for defining and running multi-container Docker applications. It allows us to define a set of services, each with its own container, and run them with a single command.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating a Docker Composer File&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To run our React JS application with Docker Composer, we need to create a Docker Composer file. This file defines the services for our application, including the React JS application and the database. Here&amp;#39;s an example of a Docker Composer file for a React JS application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;version: &amp;#39;3.7&amp;#39;

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - &amp;#39;3030:3030&amp;#39;
    volumes:
      - .:/app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This Docker Composer file defines a single service, called &lt;code&gt;app&lt;/code&gt;, which builds the Docker image using the Dockerfile in the current directory and maps port &lt;code&gt;3030&lt;/code&gt; of the container to port &lt;code&gt;3030&lt;/code&gt; of the host system.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Running the Docker Composer File&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once we have our Docker Composer file, we can run the Docker Composer file using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command starts the Docker containers for the services defined in the Docker Composer file. We can access the React JS application in the browser by navigating to &lt;code&gt;http://localhost:3030&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0042-get-started-with-building-reactjs-and-docker-a-complete-guide/running-the-docker-composer-file.png&quot; alt=&quot;Running the Docker Composer File&quot;&gt;&lt;/p&gt;
&lt;p&gt;By following these steps, we&amp;#39;ve successfully run a React JS application with Docker Composer, making it easy to develop, run, and deploy the application in a consistent and scalable way.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0042-get-started-with-building-reactjs-and-docker-a-complete-guide/showing-the-react-js-application.png&quot; alt=&quot;Showing the React JS Application&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stopping the Docker Composer File&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once we&amp;#39;re done with the React JS application, we can stop the Docker Composer file using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker-compose down -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command stops the Docker containers for the services defined in the Docker Composer file.&lt;/p&gt;
&lt;h2&gt;Containerizing the React JS Application&lt;/h2&gt;
&lt;p&gt;In this section, we&amp;#39;ll explore how to containerize a React JS application with Docker, making it easy to deploy and scale the application in any environment.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understanding Containerization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Containerization is the process of encapsulating an application and its dependencies in a self-contained environment, called a container. Containers are similar to virtual machines, but they are more lightweight and share the host operating system&amp;#39;s kernel. This makes containers faster and more efficient than traditional virtual machines.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating a Dockerfile&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To containerize our React JS application, we need to create a Dockerfile that includes all the necessary dependencies and configurations. We can use the same Dockerfile we created earlier, or we can create a new one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Building the Docker Image&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once we have our Dockerfile, we can build the Docker image using the &amp;quot;docker build&amp;quot; command. The resulting image includes all the necessary dependencies and configurations for running our React JS application in a container.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Running the Docker Container&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After building the Docker image, we can run the Docker container using the &amp;quot;docker run&amp;quot; command. This command starts a new container based on the image we just built.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Publishing the Docker Image&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To make the containerized React JS application available to others, we can publish the Docker image to a registry, such as Docker Hub. This allows others to download and run the application in a container.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deploying the Containerized Application&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, we can deploy the containerized React JS application to any environment that supports Docker, such as a local machine, a cloud provider, or a Kubernetes cluster. This makes it easy to scale the application as needed and ensures consistent behavior across different environments.&lt;/p&gt;
&lt;p&gt;By containerizing our React JS application with Docker, we can simplify the deployment process and make it easier to scale the application in any environment. This approach also ensures that the application is running in a consistent and predictable environment, which reduces the risk of unexpected issues and bugs.&lt;/p&gt;
&lt;h2&gt;Troubleshooting and Best Practices&lt;/h2&gt;
&lt;p&gt;In this section, we&amp;#39;ll explore some common issues and best practices when working with React JS and Docker.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Troubleshooting&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When working with React JS and Docker, there are a few common issues that you may encounter, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Incorrect port mapping: Make sure that the container is mapped to the correct port to access the React JS application.&lt;/li&gt;
&lt;li&gt;Missing dependencies: Ensure that all the necessary dependencies are included in the Docker image and that they are correctly installed and configured.&lt;/li&gt;
&lt;li&gt;Performance issues: If the application is running slowly or experiencing performance issues, consider scaling the application or optimizing the Docker image.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Best Practices&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To get the most out of React JS and Docker, it&amp;#39;s important to follow some best practices, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep Docker images small: Minimize the size of the Docker image by removing unnecessary dependencies and configurations.&lt;/li&gt;
&lt;li&gt;Use a .dockerignore file: Exclude unnecessary files and directories from the Docker image using a .dockerignore file to speed up the build process.&lt;/li&gt;
&lt;li&gt;Use environment variables: Use environment variables to store configuration settings and sensitive data, such as API keys and database credentials.&lt;/li&gt;
&lt;li&gt;Implement health checks: Implement health checks to monitor the status of the application and ensure that it&amp;#39;s running correctly.&lt;/li&gt;
&lt;li&gt;Use a container orchestration tool: Consider using a container orchestration tool, such as Kubernetes or Docker Swarm, to manage and scale the application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By following these best practices and troubleshooting common issues, you can ensure that your React JS application runs smoothly and efficiently in a Docker container.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this guide, we&amp;#39;ve explored how to build, containerize, and deploy a React JS application with Docker. By using Docker, we can ensure that the application runs in a consistent and scalable environment, making it easier to deploy and maintain.&lt;/p&gt;
&lt;p&gt;We started by preparing the environment for Docker and installing the necessary tools and dependencies. We then built and containerized the React JS application, ensuring that all the necessary dependencies and configurations were included in the Docker image.&lt;/p&gt;
&lt;p&gt;Next, we explored how to deploy the application to a chosen environment and scale it as needed. Finally, we looked at some best practices and troubleshooting tips for working with React JS and Docker.&lt;/p&gt;
&lt;p&gt;By following the steps outlined in this guide, you can build and deploy a React JS application with Docker, making it easier to manage and scale as your needs change. With Docker, you can focus on building great applications and leave the infrastructure to the experts.&lt;/p&gt;
&lt;h2&gt;Source Code&lt;/h2&gt;
&lt;p&gt;You can find the source code for this tutorial on GitHub.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/MKAbuMattar/react-hooks-slider&quot;&gt;SOURCE CODE&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/&quot;&gt;React JS Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/builder/&quot;&gt;Dockerfile reference - Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose overview - Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/get-started/&quot;&gt;Get started with Docker - Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://create-react-app.dev/docs/getting-started/&quot;&gt;Create React App - Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Dockerizing a React App&amp;quot; - Docker Documentation.), &lt;a href=&quot;https://www.docker.com/blog/dockerizing-a-react-app/&quot;&gt;https://www.docker.com/blog/dockerizing-a-react-app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;How To Dockerize a React Application&amp;quot; - DigitalOcean.), &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-dockerize-a-react-application&quot;&gt;https://www.digitalocean.com/community/tutorials/how-to-dockerize-a-react-application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Best practices for writing Dockerfiles&amp;quot; - Docker Documentation.), &lt;a href=&quot;https://docs.docker.com/develop/develop-images/dockerfile_best-practices/&quot;&gt;https://docs.docker.com/develop/develop-images/dockerfile_best-practices/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Using Docker Compose for Local Development with React&amp;quot; - (Example: Search for tutorials on Medium or LogRocket.), [Link to a relevant tutorial]&lt;/li&gt;
&lt;li&gt;&amp;quot;Understanding .dockerignore files&amp;quot; - Docker Documentation.), &lt;a href=&quot;https://docs.docker.com/engine/reference/builder/#dockerignore-file&quot;&gt;https://docs.docker.com/engine/reference/builder/#dockerignore-file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Environment variables in Compose&amp;quot; - Docker Documentation.), &lt;a href=&quot;https://docs.docker.com/compose/environment-variables/&quot;&gt;https://docs.docker.com/compose/environment-variables/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Healthcheck - Dockerfile reference&amp;quot; - Docker Documentation.), &lt;a href=&quot;https://docs.docker.com/engine/reference/builder/#healthcheck&quot;&gt;https://docs.docker.com/engine/reference/builder/#healthcheck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code Official Website&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>ReactJS</category><category>Docker</category><category>DevOps</category><category>Containerization</category><category>Web Development</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0042-get-started-with-building-reactjs-and-docker-a-complete-guide/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Building a Customizable Image Slider in React Using Hooks, SCSS, and TypeScript</title><link>https://mkabumattar.com/blog/post/building-a-customizable-image-slider-in-react-using-hooks-scss-and-typescript/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/building-a-customizable-image-slider-in-react-using-hooks-scss-and-typescript/</guid><description>This article will guide you through the process of creating a React slider component using Hooks, SCSS, and TypeScript. By the end of this tutorial, you will have a functional and customizable slider that can be easily integrated into your project.</description><pubDate>Fri, 17 Feb 2023 11:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this tutorial, we will be building a customizable image slider in React using hooks, SCSS, and TypeScript. An image slider is a common UI element used in web applications to display a set of images that can be scrolled or navigated through. With React, building an image slider becomes easier and more modular.&lt;/p&gt;
&lt;p&gt;Hooks are a new addition to React 16.8 that allows you to use state and other React features without writing a class. Hooks enable the creation of reusable and composable logic for React components.&lt;/p&gt;
&lt;p&gt;SCSS is a preprocessor for CSS, which makes it easier to write and maintain large stylesheets. It allows you to use variables, mixins, and functions to create more modular and maintainable styles.&lt;/p&gt;
&lt;p&gt;TypeScript is a typed superset of JavaScript that adds type annotations and other features to make it easier to catch errors and refactor code. TypeScript improves the developer experience and makes code easier to understand and maintain.&lt;/p&gt;
&lt;p&gt;By the end of this tutorial, you will have a basic understanding of how to create a customizable image slider in React using hooks, SCSS, and TypeScript. You will also learn how to create a reusable component that can be easily customized and styled to fit your needs.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before starting to build the customizable image slider in React, you should have a basic understanding of React, JavaScript, and CSS. You should be familiar with React hooks, including useState and useEffect, and have a working knowledge of TypeScript. Additionally, you should have Node.js and npm (Node Package Manager) installed on your machine, as we will be using them to set up the project and manage its dependencies.&lt;/p&gt;
&lt;p&gt;If you are new to React or TypeScript, it is recommended that you first complete some beginner-level tutorials to familiarize yourself with the fundamentals of the technologies. Once you have a solid understanding of the basics, you will be better equipped to follow along with this tutorial and build your own customizable image slider.&lt;/p&gt;
&lt;h2&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;n this section, we will guide you through setting up the project. To start with, we will create a new React project using vite. Vite is a fast and efficient build tool that enables you to develop your React application quickly. It is built on top of Rollup and ESBuild, which makes it a lightweight and user-friendly tool.&lt;/p&gt;
&lt;p&gt;To create a new project, open up your terminal and run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;npx create-vite react-hooks-slider --template react-ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will create a new React project with the name &lt;code&gt;react-hooks-slider&lt;/code&gt; using the &lt;code&gt;react-ts&lt;/code&gt; template, which includes TypeScript support. Once the project is created, navigate into the project directory using the &lt;code&gt;cd&lt;/code&gt; command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cd react-hooks-slider
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a new React project using TypeScript. After that, we will install the dependencie for SCSS. To do this, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;npm install -D sass
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have created our project, we can begin setting up our slider component using React, Hooks, SCSS, and TypeScript. In the next section, we will start by creating a new React component for our slider.&lt;/p&gt;
&lt;h2&gt;Creating the Slider Component&lt;/h2&gt;
&lt;p&gt;The first step in building our customizable image slider is to create a React component that will render our slider. We&amp;#39;ll call this component &lt;code&gt;Slider&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To create the &lt;code&gt;Slider&lt;/code&gt; component, we&amp;#39;ll first need to import React and the necessary hooks from React, including &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt;, and &lt;code&gt;useRef&lt;/code&gt;. We&amp;#39;ll also need to import any external libraries or components that we&amp;#39;ll be using in our slider.&lt;/p&gt;
&lt;p&gt;Next, we&amp;#39;ll define our Slider function component and set up its initial state using the &lt;code&gt;useState&lt;/code&gt; hook. We&amp;#39;ll keep track of the current index of the active slide and the previous and next slide indexes. We&amp;#39;ll also create a &lt;code&gt;ref&lt;/code&gt; using the &lt;code&gt;useRef&lt;/code&gt; hook that will allow us to access the container element of our slider.&lt;/p&gt;
&lt;p&gt;Then, we&amp;#39;ll set up the &lt;code&gt;useEffect&lt;/code&gt; hook to update the slider&amp;#39;s state and animate the slides whenever the current index changes. This hook will listen for changes to the current index and adjust the previous and next slide indexes accordingly. It will also update the position of the slider using CSS transforms to animate the slides.&lt;/p&gt;
&lt;h3&gt;Creating the Component Structure&lt;/h3&gt;
&lt;p&gt;In this section, we will create the basic structure of our slider component. We will start by creating a new folder called &lt;code&gt;components&lt;/code&gt; inside the &lt;code&gt;src&lt;/code&gt; folder. Inside the &lt;code&gt;components&lt;/code&gt; folder, we will create a new directory called &lt;code&gt;Slider&lt;/code&gt; and &lt;code&gt;Icons&lt;/code&gt;. The &lt;code&gt;Slider&lt;/code&gt; directory will contain the files for our slider component, and the &lt;code&gt;Icons&lt;/code&gt; directory will contain the SVG as React components.&lt;/p&gt;
&lt;p&gt;At the end of this section, our project structure will look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;react-hooks-slider
├── dist
├── node_modules
├── public
├── src
│   ├── components
│   │   ├── Icons
│   │   │   ├── RightArrowIcon.test.tsx
│   │   │   └── RightArrowIcon.tsx
│   │   └── Slider
│   │       ├── index.tsx
│   │       ├── Slide.test.tsx
│   │       ├── Slide.tsx
│   │       ├── Slider.test.tsx
│   │       ├── Slider.tsx
│   │       ├── SliderControl.test.tsx
│   │       ├── SliderControl.tsx
│   │       └── style.scss
│   ├── data
│   │   └── slider.data.json
│   ├── App.tsx
│   ├── main.tsx
│   ├── style.scss
│   └── vite-env.d.ts
├── .gitignore
├── package-lock.json
├── package.json
├── README.md
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have created our project structure, we can start creating our slider component. To do this, at first, we will create a new file called &lt;code&gt;RightArrowIcon.tsx&lt;/code&gt; inside the &lt;code&gt;Icons&lt;/code&gt; directory. This file will contain the SVG for the right arrow icon that we will use in our slider component.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import React from &amp;#39;react&amp;#39;;

// type
export type Props = {
  fill?: string;
  size?: string;
  [x: string]: any;
};

const index = (props: Props) =&amp;gt; {
  const {fill = &amp;#39;currentColor&amp;#39;, size = &amp;#39;24&amp;#39;, ...otherProps} = props;

  return (
    &amp;lt;svg
      xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot;
      width={size}
      height={size}
      viewBox=&amp;quot;0 0 24 24&amp;quot;
      fill={fill}
      {...otherProps}
    &amp;gt;
      &amp;lt;path d=&amp;quot;m11.293 17.293 1.414 1.414L19.414 12l-6.707-6.707-1.414 1.414L15.586 11H6v2h9.586z&amp;quot;&amp;gt;&amp;lt;/path&amp;gt;
    &amp;lt;/svg&amp;gt;
  );
};

export default index;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, we have created a new React component called &lt;code&gt;RightArrowIcon&lt;/code&gt;. This component will render the SVG for the right arrow icon. We have also added the &lt;code&gt;fill&lt;/code&gt; and &lt;code&gt;size&lt;/code&gt; props to the component, which will allow us to customize the color and size of the icon.&lt;/p&gt;
&lt;p&gt;Next, we will create a new file called &lt;code&gt;Slide.tsx&lt;/code&gt; inside the &lt;code&gt;Slider&lt;/code&gt; directory. This file will contain the main slider component. We will start by importing the &lt;code&gt;RightArrowIcon&lt;/code&gt; component that we created in the previous step.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;// icons
import RightArrowIcon from &amp;#39;../Icons/RightArrowIcon&amp;#39;;
import React, {useRef, useEffect, MouseEvent} from &amp;#39;react&amp;#39;;

// types
export type Tag = {
  name: string;
};

export type Link = {
  name: string;
  url: string;
};

export type SlideData = {
  index: number;
  src: string;
  headline: string;
  direction?: string;
  tags?: Tag[];
  links?: Link[];
};

export type SlideProps = {
  slide: SlideData;
  index: number;
  current: number;
  handleSlideClick: (e: MouseEvent&amp;lt;HTMLDivElement&amp;gt;) =&amp;gt; void;
};

const Slide = ({slide, index, current, handleSlideClick}: SlideProps) =&amp;gt; {
  const slideRef = useRef&amp;lt;HTMLDivElement&amp;gt;(null);

  const handleMouseMove = (e: MouseEvent&amp;lt;HTMLDivElement&amp;gt;) =&amp;gt; {
    const el = slideRef.current;
    const r = el!.getBoundingClientRect();

    el!.style.setProperty(
      &amp;#39;--x&amp;#39;,
      (e.clientX - (r.left + Math.floor(r.width / 2))).toString(),
    );
    el!.style.setProperty(
      &amp;#39;--y&amp;#39;,
      (e.clientY - (r.top + Math.floor(r.height / 2))).toString(),
    );
  };

  const handleMouseLeave = (e: MouseEvent&amp;lt;HTMLDivElement&amp;gt;) =&amp;gt; {
    const el = slideRef.current;
    if (el) {
      el.style.setProperty(&amp;#39;--x&amp;#39;, &amp;#39;0&amp;#39;);
      el.style.setProperty(&amp;#39;--y&amp;#39;, &amp;#39;0&amp;#39;);
    }
  };

  useEffect(() =&amp;gt; {
    const el = slideRef.current!.querySelector(&amp;#39;img&amp;#39;);
    el!.style.opacity = &amp;#39;1&amp;#39;;
  }, []);

  const {src, headline, direction, tags, links} = slide;
  let classNames = &amp;#39;slide&amp;#39;;

  if (current === index) classNames += &amp;#39; slide--current&amp;#39;;
  else if (current - 1 === index) classNames += &amp;#39; slide--previous&amp;#39;;
  else if (current + 1 === index) classNames += &amp;#39; slide--next&amp;#39;;

  return (
    &amp;lt;div
      ref={slideRef}
      className={classNames}
      onClick={handleSlideClick}
      onMouseMove={handleMouseMove}
      onMouseLeave={handleMouseLeave}
      data-index={index}
    &amp;gt;
      &amp;lt;div className={&amp;#39;slide__image-wrapper&amp;#39;}&amp;gt;
        &amp;lt;img className={&amp;#39;slide__image&amp;#39;} alt={headline} src={src} /&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;div className={&amp;#39;slide__overlay&amp;#39;}&amp;gt;
        &amp;lt;div className={&amp;#39;slide__content&amp;#39;}&amp;gt;
          &amp;lt;h2 className={&amp;#39;slide__content--headline&amp;#39;}&amp;gt;{headline}&amp;lt;/h2&amp;gt;

          {direction &amp;amp;&amp;amp; &amp;lt;p className={&amp;#39;&amp;#39;}&amp;gt;{direction}&amp;lt;/p&amp;gt;}

          {tags &amp;amp;&amp;amp; (
            &amp;lt;div className={&amp;#39;slide__content--tag-wrapper&amp;#39;}&amp;gt;
              Tags:{&amp;#39; &amp;#39;}
              {tags.map((tag: Tag, index: number) =&amp;gt; (
                &amp;lt;span key={index} className={&amp;#39;slide__content--tag&amp;#39;}&amp;gt;
                  {tag?.name}
                &amp;lt;/span&amp;gt;
              ))}
            &amp;lt;/div&amp;gt;
          )}

          &amp;lt;div className={&amp;#39;slide__content--button-wrapper&amp;#39;}&amp;gt;
            {links?.map((link: Link, index: number) =&amp;gt; (
              &amp;lt;a
                key={index}
                className={&amp;#39;slide__content--button&amp;#39;}
                href={link?.url}
                target={&amp;#39;__blank&amp;#39;}
              &amp;gt;
                {link?.name}{&amp;#39; &amp;#39;}
                &amp;lt;span className={&amp;#39;slide__content--button__icon&amp;#39;}&amp;gt;
                  &amp;lt;RightArrowIcon /&amp;gt;
                &amp;lt;/span&amp;gt;
              &amp;lt;/a&amp;gt;
            ))}
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Slide;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, we have created a new React component called &lt;code&gt;Slide&lt;/code&gt;. This component will render the main slider component. We have also added the &lt;code&gt;slide&lt;/code&gt;, &lt;code&gt;index&lt;/code&gt;, &lt;code&gt;current&lt;/code&gt;, and &lt;code&gt;handleSlideClick&lt;/code&gt; props to the component, which will allow us to pass the data for the slider and handle the click event on the slider.&lt;/p&gt;
&lt;p&gt;Next, we will create a new file called &lt;code&gt;SliderControl.tsx&lt;/code&gt; inside the &lt;code&gt;Slider&lt;/code&gt; directory. This file will contain the main slider component. We will start by importing the &lt;code&gt;Slide&lt;/code&gt; component that we created in the previous step.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import React, {MouseEvent} from &amp;#39;react&amp;#39;;

// types
export type SliderControlProps = {
  type: string;
  title: string;
  handleClick: (e: MouseEvent&amp;lt;HTMLButtonElement&amp;gt;) =&amp;gt; void;
};

const SliderControl = ({type, title, handleClick}: SliderControlProps) =&amp;gt; {
  return (
    &amp;lt;button className={`btn btn--${type}`} title={title} onClick={handleClick}&amp;gt;
      &amp;lt;svg className={&amp;#39;icon&amp;#39;} viewBox={&amp;#39;0 0 24 24&amp;#39;}&amp;gt;
        &amp;lt;path d=&amp;quot;M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z&amp;quot; /&amp;gt;
      &amp;lt;/svg&amp;gt;
    &amp;lt;/button&amp;gt;
  );
};

export default SliderControl;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, we have created a new React component called &lt;code&gt;SliderControl&lt;/code&gt;. This component will render the slider control buttons. We have also added the &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, and &lt;code&gt;handleClick&lt;/code&gt; props to the component, which will allow us to pass the data for the slider control buttons and handle the click event on the slider control buttons.&lt;/p&gt;
&lt;p&gt;Next, we will create a new file called &lt;code&gt;Slider.tsx&lt;/code&gt; inside the &lt;code&gt;Slider&lt;/code&gt; directory. This file will contain the main slider component. We will start by importing the &lt;code&gt;Slide&lt;/code&gt; and &lt;code&gt;SliderControl&lt;/code&gt; components that we created in the previous steps.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import Slide, {SlideData} from &amp;#39;./Slide&amp;#39;;
import SliderControl from &amp;#39;./SliderControl&amp;#39;;
import React, {useState, MouseEvent} from &amp;#39;react&amp;#39;;

export type SliderProps = {
  slides: SlideData[];
  heading: string;
};

const Slider = ({slides, heading}: SliderProps) =&amp;gt; {
  const [current, setCurrent] = useState(0);
  const headingId = `slider-heading__${heading
    .replace(/\s+/g, &amp;#39;-&amp;#39;)
    .toLowerCase()}`;
  const wrapperTransform = {
    transform: `translateX(-${current * (100 / slides.length)}%)`,
  };

  const handlePreviousClick = () =&amp;gt; {
    const previous = current - 1;

    setCurrent(previous &amp;lt; 0 ? slides.length - 1 : previous);
  };

  const handleNextClick = () =&amp;gt; {
    const next = current + 1;

    setCurrent(next === slides.length ? 0 : next);
  };

  const handleSlideClick = (e: MouseEvent&amp;lt;HTMLDivElement&amp;gt;) =&amp;gt; {
    const index = e.currentTarget?.getAttribute(&amp;#39;data-index&amp;#39;);
    if (index &amp;amp;&amp;amp; current !== +index) {
      setCurrent(+index);
    }
  };

  return (
    &amp;lt;&amp;gt;
      &amp;lt;div className={&amp;#39;slider&amp;#39;} aria-labelledby={headingId}&amp;gt;
        &amp;lt;div className={&amp;#39;slider__wrapper&amp;#39;} style={wrapperTransform}&amp;gt;
          &amp;lt;h3 id={headingId} className={&amp;#39;visuallyhidden&amp;#39;}&amp;gt;
            {heading}
          &amp;lt;/h3&amp;gt;

          {slides.map((slide, index: number) =&amp;gt; (
            &amp;lt;Slide
              key={index}
              index={index}
              slide={slide}
              current={current}
              handleSlideClick={handleSlideClick}
            /&amp;gt;
          ))}
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;div className={&amp;#39;slider__controls&amp;#39;}&amp;gt;
        &amp;lt;SliderControl
          type={&amp;#39;previous&amp;#39;}
          title={&amp;#39;Go to previous slide&amp;#39;}
          handleClick={handlePreviousClick}
        /&amp;gt;

        &amp;lt;SliderControl
          type={&amp;#39;next&amp;#39;}
          title={&amp;#39;Go to next slide&amp;#39;}
          handleClick={handleNextClick}
        /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

export default Slider;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, we have created a new React component called &lt;code&gt;Slider&lt;/code&gt;. This component will render the main slider component. We have also added the &lt;code&gt;slides&lt;/code&gt; and &lt;code&gt;heading&lt;/code&gt; props to the component, which will allow us to pass the data for the slider.&lt;/p&gt;
&lt;p&gt;Next, we will create a new file called &lt;code&gt;index.tsx&lt;/code&gt; inside the &lt;code&gt;Slider&lt;/code&gt; directory. This file will contain the main slider component. We will start by importing the &lt;code&gt;Slider&lt;/code&gt; component that we created in the previous step.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import {SlideData} from &amp;#39;./Slide&amp;#39;;
import Slider from &amp;#39;./Slider&amp;#39;;
import &amp;#39;./style.scss&amp;#39;;
import React from &amp;#39;react&amp;#39;;

const SliderComponent = ({
  slides,
  heading,
}: {
  slides: SlideData[];
  heading: string;
}) =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Slider slides={slides} heading={heading} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default SliderComponent;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, we have created a new React component called &lt;code&gt;SliderComponent&lt;/code&gt;. This component will render the main slider component. We have also added the &lt;code&gt;slides&lt;/code&gt; and &lt;code&gt;heading&lt;/code&gt; props to the component, which will allow us to pass the data for the slider.&lt;/p&gt;
&lt;p&gt;Next, we will create a new file called &lt;code&gt;style.scss&lt;/code&gt; inside the &lt;code&gt;Slider&lt;/code&gt; directory. This file will contain the main slider component styles.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-scss&quot;&gt;:root {
  --color-primary: #6b7a8f;
  --color-secondary: #101118;
  --color-accent: #1d1f2f;
  --color-focus: #6d64f7;
  --base-duration: 600ms;
  --base-ease: cubic-bezier(0.25, 0.46, 0.45, 0.84);
}

.visuallyhidden {
  clip: rect(0.0625rem, 0.0625rem, 0.0625rem, 0.0625rem);
  height: 0.0625rem;
  overflow: hidden;
  position: absolute !important;
  white-space: nowrap;
  width: 0.0625rem;
}

.icon {
  fill: var(--color-primary);
  width: 100%;
}

.btn {
  background-color: var(--color-primary);
  border: none;
  border-radius: 0.125rem;
  color: white;
  cursor: pointer;
  font-family: inherit;
  font-size: inherit;
  padding: 1rem 2.5rem 1.125rem;

  &amp;amp;:focus {
    outline-color: var(--color-focus);
    outline-offset: 0.125rem;
    outline-style: solid;
    outline-width: 0.1875rem;
  }

  &amp;amp;:active {
    transform: translateY(0.0625rem);
  }
}

.slider {
  --slide-size: 55vmin;
  --slide-margin: 4vmin;
  height: var(--slide-size);
  width: var(--slide-size);
  margin: 0 auto;
  position: relative;

  &amp;amp;__wrapper {
    display: flex;
    margin: 0 calc(var(--slide-margin) * -1);
    position: absolute;
    transition: transform var(--base-duration) cubic-bezier(0.25, 1, 0.35, 1);
  }

  &amp;amp;__controls {
    display: flex;
    justify-content: center;
    width: 100%;
    margin-top: 0.5rem;

    .btn {
      --size: 3rem;
      align-items: center;
      background-color: transparent;
      border: 0.188rem solid transparent;
      border-radius: 100%;
      display: flex;
      height: var(--size);
      width: var(--size);
      padding: 0;

      &amp;amp;:focus {
        border-color: var(--color-focus);
        outline: none;
      }

      &amp;amp;--previous {
        &amp;gt; * {
          transform: rotate(180deg);
        }
      }
    }
  }
}

.slide {
  align-items: center;
  color: white;
  display: flex;
  flex: 1;
  flex-direction: column;
  height: var(--slide-size);
  justify-content: center;
  margin: 0 var(--slide-margin);
  opacity: 0.25;
  position: relative;
  text-align: center;
  transition:
    opacity calc(var(--base-duration) / 2) var(--base-ease),
    transform calc(var(--base-duration) / 2) var(--base-ease);
  width: var(--slide-size);
  z-index: 1;

  &amp;amp;__image {
    --d: 20;
    height: 110%;
    -o-object-fit: cover;
    object-fit: cover;
    opacity: 0;
    pointer-events: none;
    transition:
      opacity var(--base-duration) var(--base-ease),
      transform var(--base-duration) var(--base-ease);
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    width: 110%;

    &amp;amp;-wrapper {
      background-color: var(--color-accent);
      border-radius: 1%;
      height: 100%;
      left: 0%;
      overflow: hidden;
      position: absolute;
      top: 0%;
      transition: transform calc(var(--base-duration) / 4) var(--base-ease);
      width: 100%;
    }
  }

  &amp;amp;__overlay {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    height: 100%;
    width: 100%;
    transition: 0.5s ease;
    background-color: #00000080;
    transition: transform calc(var(--base-duration) / 4) var(--base-ease);
  }

  &amp;amp;__content {
    --d: 60;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    opacity: 0;
    padding: 1rem;
    position: relative;
    transition: transform var(--base-duration) var(--base-ease);
    visibility: hidden;

    &amp;amp;--headline {
      font-size: 3rem;
      font-weight: 600;
      position: relative;
      color: white;
    }

    &amp;amp;--tag {
      display: flex;
      justify-content: center;
      align-items: center;
      gap: 0.3rem;

      &amp;amp;-wrapper {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 0.5rem;
        margin-top: 0.5rem;
        user-select: none;
      }
    }

    &amp;amp;--button {
      width: max-content;
      color: var(--first-color);
      font-size: var(--small-font-size);
      display: flex;
      align-items: center;
      column-gap: 0.25rem;

      &amp;amp;-wrapper {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 0.5rem;
        margin-top: 0.5rem;
        user-select: none;
      }

      &amp;amp;__icon {
        width: 1rem;
        height: 1rem;
        transition: 0.4s;

        svg {
          width: 1rem;
          height: 1rem;
        }
      }

      &amp;amp;:hover &amp;amp;__icon {
        transform: translateX(0.25rem);
      }
    }
  }

  &amp;amp;--previous {
    &amp;amp;:hover {
      opacity: 0.5;
      transform: translateX(2%);
    }
    cursor: w-resize;
  }

  &amp;amp;--current {
    --x: 0;
    --y: 0;
    --d: 50;
    opacity: 1;
    pointer-events: auto;
    -webkit-user-select: auto;
    -moz-user-select: auto;
    -ms-user-select: auto;
    user-select: auto;

    .slide {
      &amp;amp;__content {
        -webkit-animation: fade-in calc(var(--base-duration) / 2)
          var(--base-ease) forwards;
        animation: fade-in calc(var(--base-duration) / 2) var(--base-ease)
          forwards;
        visibility: visible;
      }
    }
  }

  &amp;amp;--next {
    &amp;amp;:hover {
      opacity: 0.5;
      transform: translateX(-2%);
    }
    cursor: e-resize;
  }
}

@media screen and (max-width: 568px) {
  .slider {
    --slide-size: 90vmin;
  }
}

@media (hover: hover) {
  .slide {
    &amp;amp;--current {
      &amp;amp;:hover {
        .slide {
          &amp;amp;__image {
            &amp;amp;-wrapper {
              transform: scale(1.025)
                translate(
                  calc(var(--x) / var(--d) * 0.063rem),
                  calc(var(--y) / var(--d) * 0.063rem)
                );
            }
          }

          &amp;amp;__overlay {
            transform: scale(1.025)
              translate(
                calc(var(--x) / var(--d) * 0.063rem),
                calc(var(--y) / var(--d) * 0.063rem)
              );
          }
        }
      }
      .slide {
        &amp;amp;__image {
          transform: translate(
            calc(var(--x) / var(--d) * 0.063rem),
            calc(var(--y) / var(--d) * 0.063rem)
          );
        }

        &amp;amp;__content {
          transform: translate(
            calc(var(--x) / var(--d) * -0.063rem),
            calc(var(--y) / var(--d) * -0.063rem)
          );
        }
      }
    }
  }
  .slide {
    &amp;amp;__overlay {
      transform: translate(
        calc(var(--x) / var(--d) * 0.063rem),
        calc(var(--y) / var(--d) * 0.063rem)
      );
    }
  }
}

@-webkit-keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Running the Slider Component&lt;/h3&gt;
&lt;p&gt;Now that we have the slider component, we need to add it at &lt;code&gt;App.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;// Import the slider component
import Slider from &amp;#39;./components/Slider&amp;#39;;
// Import the slide data type
import {SlideData} from &amp;#39;./components/Slider/Slide&amp;#39;;
// Import the slider data
import sliderData from &amp;#39;./data/slider.data.json&amp;#39;;
import &amp;#39;./style.scss&amp;#39;;
import React from &amp;#39;react&amp;#39;;

const App = () =&amp;gt; {
  return (
    &amp;lt;div className=&amp;quot;app&amp;quot;&amp;gt;
      &amp;lt;Slider
        slides={sliderData.slides as SlideData[]}
        heading={sliderData.heading}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can run the command &lt;code&gt;npm run dev&lt;/code&gt; to run the application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After running the command, you will see the slider component in the home page:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0041-building-a-customizable-image-slider-in-react-using-hooks-scss-and-typescript/slider-component-demo.png&quot; alt=&quot;Slider component&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Testing the Slider Component&lt;/h3&gt;
&lt;p&gt;To start testing the slider component, we will need to install some dependencies. Run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;npm install --save-dev @testing-library/jest-dom @testing-library/react @types/jest jest ts-jest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After installing the dependencies, we will add the &lt;code&gt;jest&lt;/code&gt; at &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json:package.json&quot;&gt;{
  ...,
  &amp;quot;jest&amp;quot;: {
    &amp;quot;transform&amp;quot;: {
      &amp;quot;^.+\\.tsx$&amp;quot;: &amp;quot;ts-jest&amp;quot;,
      &amp;quot;^.+\\.ts$&amp;quot;: &amp;quot;ts-jest&amp;quot;
    },
    &amp;quot;testEnvironment&amp;quot;: &amp;quot;jest-environment-jsdom&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have the slider component, we can test it. We will use the slider component in the home page. Open the &lt;code&gt;src/components/Icons/RightArrowIcon.test.tsx&lt;/code&gt; file and add the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import RightArrowIcon from &amp;#39;./RightArrowIcon&amp;#39;;
import &amp;#39;@testing-library/jest-dom&amp;#39;;
import {render} from &amp;#39;@testing-library/react&amp;#39;;
import React from &amp;#39;react&amp;#39;;

describe(&amp;#39;RightArrowIcon&amp;#39;, () =&amp;gt; {
  test(&amp;#39;renders&amp;#39;, () =&amp;gt; {
    const {container} = render(&amp;lt;RightArrowIcon /&amp;gt;);
    expect(container.firstChild).toBeInTheDocument();
  });

  test(&amp;#39;has correct fill&amp;#39;, () =&amp;gt; {
    const {container} = render(&amp;lt;RightArrowIcon fill=&amp;quot;red&amp;quot; /&amp;gt;);
    expect(container.firstChild).toHaveAttribute(&amp;#39;fill&amp;#39;, &amp;#39;red&amp;#39;);
  });

  test(&amp;#39;has correct size&amp;#39;, () =&amp;gt; {
    const {container} = render(&amp;lt;RightArrowIcon size=&amp;quot;24&amp;quot; /&amp;gt;);
    expect(container.firstChild).toHaveAttribute(&amp;#39;width&amp;#39;, &amp;#39;24&amp;#39;);
    expect(container.firstChild).toHaveAttribute(&amp;#39;height&amp;#39;, &amp;#39;24&amp;#39;);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we will add the slider component to the home page. Open the &lt;code&gt;SliderControl.test.tsx&lt;/code&gt; file and add the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import SliderControl from &amp;#39;./SliderControl&amp;#39;;
import &amp;#39;@testing-library/jest-dom&amp;#39;;
import {render, fireEvent} from &amp;#39;@testing-library/react&amp;#39;;
import React from &amp;#39;react&amp;#39;;

describe(&amp;#39;SliderControl component&amp;#39;, () =&amp;gt; {
  it(&amp;#39;should render the correct title and type&amp;#39;, () =&amp;gt; {
    const handleClick = jest.fn();
    const {getByTitle} = render(
      &amp;lt;SliderControl
        type=&amp;quot;prev&amp;quot;
        title=&amp;quot;Previous slide&amp;quot;
        handleClick={handleClick}
      /&amp;gt;,
    );

    expect(getByTitle(&amp;#39;Previous slide&amp;#39;)).toBeInTheDocument();
    expect(getByTitle(&amp;#39;Previous slide&amp;#39;)).toHaveClass(&amp;#39;btn--prev&amp;#39;);
  });

  it(&amp;#39;should call the handleClick function when clicked&amp;#39;, () =&amp;gt; {
    const handleClick = jest.fn();
    const {getByTitle} = render(
      &amp;lt;SliderControl
        type=&amp;quot;next&amp;quot;
        title=&amp;quot;Next slide&amp;quot;
        handleClick={handleClick}
      /&amp;gt;,
    );

    fireEvent.click(getByTitle(&amp;#39;Next slide&amp;#39;));
    expect(handleClick).toHaveBeenCalled();
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we will add the slider component to the home page. Open the &lt;code&gt;Slide.test.tsx&lt;/code&gt; file and add the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import Slide, {SlideData} from &amp;#39;./Slide&amp;#39;;
import &amp;#39;@testing-library/jest-dom&amp;#39;;
import {render, fireEvent} from &amp;#39;@testing-library/react&amp;#39;;
import React from &amp;#39;react&amp;#39;;

const slideData: SlideData = {
  index: 0,
  src: &amp;#39;test-image.jpg&amp;#39;,
  headline: &amp;#39;Test Headline&amp;#39;,
  direction: &amp;#39;Test Direction&amp;#39;,
  tags: [{name: &amp;#39;Tag 1&amp;#39;}, {name: &amp;#39;Tag 2&amp;#39;}],
  links: [
    {name: &amp;#39;Link 1&amp;#39;, url: &amp;#39;http://test.com&amp;#39;},
    {name: &amp;#39;Link 2&amp;#39;, url: &amp;#39;http://test2.com&amp;#39;},
  ],
};

describe(&amp;#39;Slide component&amp;#39;, () =&amp;gt; {
  test(&amp;#39;renders with slide data&amp;#39;, () =&amp;gt; {
    const {getByText, getByAltText} = render(
      &amp;lt;Slide
        slide={slideData}
        index={0}
        current={0}
        handleSlideClick={jest.fn()}
      /&amp;gt;,
    );
    expect(getByAltText(&amp;#39;Test Headline&amp;#39;)).toBeInTheDocument();
    expect(getByText(&amp;#39;Test Headline&amp;#39;)).toBeInTheDocument();
    expect(getByText(&amp;#39;Test Direction&amp;#39;)).toBeInTheDocument();
    expect(getByText(&amp;#39;Tags:&amp;#39;)).toBeInTheDocument();
    expect(getByText(&amp;#39;Tag 1&amp;#39;)).toBeInTheDocument();
    expect(getByText(&amp;#39;Tag 2&amp;#39;)).toBeInTheDocument();
    expect(getByText(&amp;#39;Link 1&amp;#39;)).toHaveAttribute(&amp;#39;href&amp;#39;, &amp;#39;http://test.com&amp;#39;);
    expect(getByText(&amp;#39;Link 2&amp;#39;)).toHaveAttribute(&amp;#39;href&amp;#39;, &amp;#39;http://test2.com&amp;#39;);
  });

  test(&amp;#39;adds slide--current class when current prop matches index prop&amp;#39;, () =&amp;gt; {
    const {container} = render(
      &amp;lt;Slide
        slide={slideData}
        index={0}
        current={0}
        handleSlideClick={jest.fn()}
      /&amp;gt;,
    );
    expect(container.firstChild).toHaveClass(&amp;#39;slide slide--current&amp;#39;);
  });

  test(&amp;#39;adds slide--next class when current prop is 1 less than index prop&amp;#39;, () =&amp;gt; {
    const {container} = render(
      &amp;lt;Slide
        slide={slideData}
        index={1}
        current={0}
        handleSlideClick={jest.fn()}
      /&amp;gt;,
    );
    expect(container.firstChild).toHaveClass(&amp;#39;slide slide--next&amp;#39;);
  });

  test(&amp;#39;adds slide--previous class when current prop is 1 more than index prop&amp;#39;, () =&amp;gt; {
    const {container} = render(
      &amp;lt;Slide
        slide={slideData}
        index={0}
        current={1}
        handleSlideClick={jest.fn()}
      /&amp;gt;,
    );
    expect(container.firstChild).toHaveClass(&amp;#39;slide slide--previous&amp;#39;);
  });

  test(&amp;#39;calls handleSlideClick function when clicked&amp;#39;, () =&amp;gt; {
    const mockHandleSlideClick = jest.fn();
    const {container} = render(
      &amp;lt;Slide
        slide={slideData}
        index={0}
        current={0}
        handleSlideClick={mockHandleSlideClick}
      /&amp;gt;,
    );
    fireEvent.click(container.firstChild!);
    expect(mockHandleSlideClick).toHaveBeenCalled();
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we will add the slider component to the home page. Open the &lt;code&gt;Slider.test.tsx&lt;/code&gt; file and add the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import {SlideData} from &amp;#39;./Slide&amp;#39;;
import Slider from &amp;#39;./Slider&amp;#39;;
import &amp;#39;@testing-library/jest-dom&amp;#39;;
import {render, fireEvent} from &amp;#39;@testing-library/react&amp;#39;;
import React from &amp;#39;react&amp;#39;;

describe(&amp;#39;Slider&amp;#39;, () =&amp;gt; {
  const slides = [
    {
      src: &amp;#39;img1.jpg&amp;#39;,
      headline: &amp;#39;Test Headline&amp;#39;,
      direction: &amp;#39;Test Direction&amp;#39;,
      tags: [{name: &amp;#39;Tag 1&amp;#39;}, {name: &amp;#39;Tag 2&amp;#39;}],
      links: [
        {name: &amp;#39;Link 1&amp;#39;, url: &amp;#39;http://test.com&amp;#39;},
        {name: &amp;#39;Link 2&amp;#39;, url: &amp;#39;http://test2.com&amp;#39;},
      ],
    },
    {
      src: &amp;#39;img2.jpg&amp;#39;,
      headline: &amp;#39;Test Headline 2&amp;#39;,
      direction: &amp;#39;Test Direction 2&amp;#39;,
      tags: [{name: &amp;#39;Tag 3&amp;#39;}, {name: &amp;#39;Tag 4&amp;#39;}],
      links: [
        {name: &amp;#39;Link 3&amp;#39;, url: &amp;#39;http://test3.com&amp;#39;},
        {name: &amp;#39;Link 4&amp;#39;, url: &amp;#39;http://test4.com&amp;#39;},
      ],
    },
    {
      src: &amp;#39;img3.jpg&amp;#39;,
      headline: &amp;#39;Test Headline 3&amp;#39;,
      direction: &amp;#39;Test Direction 3&amp;#39;,
      tags: [{name: &amp;#39;Tag 5&amp;#39;}, {name: &amp;#39;Tag 6&amp;#39;}],
      links: [
        {name: &amp;#39;Link 5&amp;#39;, url: &amp;#39;http://test5.com&amp;#39;},
        {name: &amp;#39;Link 6&amp;#39;, url: &amp;#39;http://test6.com&amp;#39;},
      ],
    },
  ] as SlideData[];

  it(&amp;#39;should render a slider with slides and controls&amp;#39;, () =&amp;gt; {
    const {getByText, getAllByRole} = render(
      &amp;lt;Slider slides={slides} heading={&amp;#39;Test Slider&amp;#39;} /&amp;gt;,
    );

    expect(getByText(&amp;#39;Test Slider&amp;#39;)).toBeInTheDocument();
    expect(getAllByRole(&amp;#39;img&amp;#39;).length).toBe(3);
    expect(getAllByRole(&amp;#39;button&amp;#39;).length).toBe(2);
  });

  it(&amp;#39;should go to the next slide when clicking the &amp;quot;next&amp;quot; control&amp;#39;, () =&amp;gt; {
    const {getAllByRole} = render(
      &amp;lt;Slider slides={slides} heading={&amp;#39;Test Slider&amp;#39;} /&amp;gt;,
    );
    const nextButton = getAllByRole(&amp;#39;button&amp;#39;)[1];

    fireEvent.click(nextButton);
    expect(getAllByRole(&amp;#39;img&amp;#39;)[1]).toHaveAttribute(&amp;#39;alt&amp;#39;, &amp;#39;Test Headline 2&amp;#39;);
  });

  it(&amp;#39;should go to the previous slide when clicking the &amp;quot;previous&amp;quot; control&amp;#39;, () =&amp;gt; {
    const {getAllByRole} = render(
      &amp;lt;Slider slides={slides} heading={&amp;#39;Test Slider&amp;#39;} /&amp;gt;,
    );
    const previousButton = getAllByRole(&amp;#39;button&amp;#39;)[0];

    fireEvent.click(previousButton);
    expect(getAllByRole(&amp;#39;img&amp;#39;)[2]).toHaveAttribute(&amp;#39;alt&amp;#39;, &amp;#39;Test Headline 3&amp;#39;);
  });

  it(&amp;#39;should go to the clicked slide when clicking a slide&amp;#39;, () =&amp;gt; {
    const {getAllByRole} = render(
      &amp;lt;Slider slides={slides} heading={&amp;#39;Test Slider&amp;#39;} /&amp;gt;,
    );
    const slide = getAllByRole(&amp;#39;img&amp;#39;)[1];

    fireEvent.click(slide);
    expect(getAllByRole(&amp;#39;img&amp;#39;)[1]).toHaveAttribute(&amp;#39;alt&amp;#39;, &amp;#39;Test Headline 2&amp;#39;);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After adding the tests, we will run the tests and see if they pass, but before that, we will add the &lt;code&gt;scripts&lt;/code&gt; at &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  ...,
  &amp;quot;scripts&amp;quot;: {
    ...,
    &amp;quot;test&amp;quot;: &amp;quot;jest&amp;quot;,
    &amp;quot;test:coverage&amp;quot;: &amp;quot;jest --coverage&amp;quot;
  },
  ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we will run the tests:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;npm run test
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we&amp;#39;ve walked through the process of building a customizable image slider in React using hooks, SCSS, and TypeScript. We started by setting up our project, creating a slider component, and implementing basic functionality to switch between images. We then added options to customize the behavior and appearance of the slider, such as Wloop, and navigation buttons.&lt;/p&gt;
&lt;p&gt;Along the way, we learned about key React concepts such as props, state, and useEffect, as well as how to use hooks to manage component state and effects. We also saw how to use SCSS to write more expressive and reusable CSS styles, and how to leverage TypeScript to add type safety and improve code readability.&lt;/p&gt;
&lt;p&gt;We hope this tutorial has been useful and informative, and that you now feel more comfortable building React applications with hooks, SCSS, and TypeScript. Happy coding!&lt;/p&gt;
&lt;h2&gt;Source Code&lt;/h2&gt;
&lt;p&gt;You can find the source code for this tutorial on GitHub.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/MKAbuMattar/react-hooks-slider&quot;&gt;SOURCE CODE&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Live Demo&lt;/h2&gt;
&lt;p&gt;You can find the live demo for this tutorial on Vercel.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://react-hooks-slider.vercel.app/&quot;&gt;LIVE DEMO&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-intro.html&quot;&gt;React Official Website - Hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sass-lang.com/&quot;&gt;SCSS (Sass) Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest Official Website - Testing Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro/&quot;&gt;React Testing Library Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform&quot;&gt;MDN Web Docs - CSS Transforms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial&quot;&gt;MDN Web Docs - SVG Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-state.html&quot;&gt;Using State Hook - React Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-effect.html&quot;&gt;Using Effect Hook - React Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#useref&quot;&gt;Using Ref Hook - React Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Creating a Reusable Component in React&amp;quot; - (Example: Search for tutorials on Smashing Magazine or LogRocket.), [Link to a relevant tutorial]&lt;/li&gt;
&lt;li&gt;&amp;quot;Styling React Components with SCSS&amp;quot; - (Example: Article from a frontend development blog.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Unit Testing React Components with Jest and React Testing Library&amp;quot; - (Example: Tutorial from DigitalOcean or a testing-focused blog.), [Link to a relevant tutorial]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>ReactJS</category><category>TypeScript</category><category>SCSS</category><category>Frontend Development</category><category>UI Components</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0041-building-a-customizable-image-slider-in-react-using-hooks-scss-and-typescript/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Run MySQL in a Docker Container: A Step-by-Step Guide with Customization Tips</title><link>https://mkabumattar.com/blog/post/how-to-run-mysql-in-a-docker-container-a-step-by-step-guide-with-customization-tips/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-run-mysql-in-a-docker-container-a-step-by-step-guide-with-customization-tips/</guid><description>Learn how to run a MySQL database in a Docker container with this step-by-step guide. The article covers starting a container, connecting to it, customizing its configuration, and using volumes for data persistence. Get tips for optimizing and customizing your setup. Ideal for developers, sysadmins and database administrators.</description><pubDate>Sun, 12 Feb 2023 14:52:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Docker has revolutionized the way we run and manage applications by making it easy to package, deploy, and run applications in containers. Containers allow applications to run in a consistent environment, independent of the host system, making it easier to manage and deploy applications.&lt;/p&gt;
&lt;p&gt;MySQL is one of the most widely used databases in the world, and it can be easily run in a Docker container. Running MySQL in a Docker container provides several benefits, including increased portability, easier management, and the ability to run multiple instances of the database on the same host.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll cover the basics of running a MySQL database in a Docker container, including how to start a container, connect to it, customize the configuration, and persist data using Docker volumes. We&amp;#39;ll also provide tips for optimizing and customizing your MySQL container setup. Whether you&amp;#39;re a developer, system administrator, or database administrator, this guide will help you get started with using Docker to run and manage your MySQL database.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before you can run a MySQL database in a Docker container, you&amp;#39;ll need to have a few things set up on your machine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker: Make sure you have Docker installed on your machine. If you don&amp;#39;t have Docker installed, you can follow the instructions for your operating system from the Docker website &lt;a href=&quot;/blog/post/how-to-install-docker-on-linux-in-4-easy-steps&quot;&gt;How To Run MySQL in a Docker Container: A Step-by-Step Guide with Customization Tips&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Docker CLI: You&amp;#39;ll also need the Docker CLI installed on your machine. This is included in the Docker installation package for most operating systems.&lt;/li&gt;
&lt;li&gt;Basic knowledge of Docker: To follow this guide, you should have a basic understanding of how Docker works and how to use the Docker CLI.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you have these prerequisites in place, you&amp;#39;re ready to start running a MySQL database in a Docker container.&lt;/p&gt;
&lt;h2&gt;Running and Setup MySQL Database in a Docker Container&lt;/h2&gt;
&lt;h3&gt;Step 1: Running a MySQL Container with the Docker Run Command&lt;/h3&gt;
&lt;p&gt;To run a MySQL container, you can use the Docker run command. The run command is used to start a new container from an image. You can use the official MySQL image from the Docker Hub to start a new container.&lt;/p&gt;
&lt;p&gt;The basic syntax of the Docker run command is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To run a MySQL container, you can use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run --name [CONTAINER_NAME] -e MYSQL_ROOT_PASSWORD=[ROOT_PASSWORD] -d mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we are using the following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--name&lt;/code&gt;: This option is used to specify a name for the container. You can replace &lt;code&gt;[CONTAINER_NAME]&lt;/code&gt; with the name you want to give to the container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt;: This option is used to set an environment variable. In this case, we&amp;#39;re setting the &lt;code&gt;MYSQL_ROOT_PASSWORD&lt;/code&gt; environment variable to the root password for the MySQL database. You can replace &lt;code&gt;[ROOT_PASSWORD]&lt;/code&gt; with the password you want to use.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt;: This option is used to run the container in the background.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This command will download the official MySQL image from the Docker Hub, start a new container with the specified name, set the root password, and run the container in the background.&lt;/p&gt;
&lt;p&gt;Once the container is running, you can use the Docker ps command to view a list of running containers and verify that your MySQL container is running.&lt;/p&gt;
&lt;h4&gt;Example&lt;/h4&gt;
&lt;p&gt;Here&amp;#39;s an example command that runs a MySQL container with the username mkabumattar and password 121612:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a MySQL container
docker run --name mysql-container -e MYSQL_ROOT_PASSWORD=121612 -e MYSQL_USER=mkabumattar -e MYSQL_PASSWORD=121612 -e MYSQL_DATABASE=mydb -p 33060:3306 -d mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we&amp;#39;re using the following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;--name&lt;/code&gt;: This option is used to specify the name of the container. We&amp;#39;re using the name mysql-container in this example.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-e&lt;/code&gt;: This option is used to set environment variables for the container. We&amp;#39;re setting the following environment variables in this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MYSQL_ROOT_PASSWORD&lt;/code&gt;: This sets the password for the root user. We&amp;#39;re setting this to &lt;code&gt;121612&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MYSQL_USER&lt;/code&gt;: This sets the username for a new user. We&amp;#39;re setting this to &lt;code&gt;mkabumattar&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MYSQL_PASSWORD&lt;/code&gt;: This sets the password for the new user. We&amp;#39;re setting this to &lt;code&gt;121612&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MYSQL_DATABASE&lt;/code&gt;: This creates a new database with the specified name. We&amp;#39;re creating a database named &lt;code&gt;mydb&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-p&lt;/code&gt;: This option is used to map a port from the host to the container. We&amp;#39;re mapping port 33060 on the host to port 3306 on the container. This allows us to connect to the MySQL container from the host machine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-d&lt;/code&gt;: This option is used to run the container in the background.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you run this command, Docker will download the MySQL image if it&amp;#39;s not already present on your system and run the container. You can then connect to the MySQL container using the mysql client as described in Step 2.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0040-how-to-run-mysql-in-a-docker-container-a-step-by-step-guide-with-customization-tips/running-mysql-container.png&quot; alt=&quot;Running a MySQL Container&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Step 2: Connecting to the MySQL Container&lt;/h3&gt;
&lt;p&gt;Once your MySQL container is running, you can connect to it using the MySQL client. The MySQL client is a command-line tool that allows you to interact with the MySQL database.&lt;/p&gt;
&lt;p&gt;To connect to the MySQL container, you&amp;#39;ll need to know the hostname and port of the container. The hostname is the name of the container, and the default port for MySQL is 3306.&lt;/p&gt;
&lt;p&gt;The basic syntax for connecting to a MySQL container using the MySQL client is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mysql -u [USERNAME] -p -h [HOSTNAME] -P [PORT]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we&amp;#39;re using the following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt;: This option is used to specify the username to use when connecting to the database. By default, the MySQL container uses the root user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt;: This option is used to prompt for a password. You&amp;#39;ll need to enter the root password you set when running the container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt;: This option is used to specify the hostname of the container. You can replace &lt;code&gt;[HOSTNAME]&lt;/code&gt; with the name of your container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-P&lt;/code&gt;: This option is used to specify the port to use when connecting to the container. By default, the MySQL container uses port 3306.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you run this command, you&amp;#39;ll be prompted for the root password. Once you enter the correct password, you&amp;#39;ll be connected to the MySQL container and can start interacting with the database.&lt;/p&gt;
&lt;p&gt;You can then run SQL commands to create databases, tables, and perform other tasks within the MySQL container.&lt;/p&gt;
&lt;h4&gt;Example&lt;/h4&gt;
&lt;p&gt;Here&amp;#39;s an example command that connects to the MySQL container using the username mkabumattar and password 121612:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mysql -h 127.0.0.1 -P 33060 -u mkabumattar -p
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we&amp;#39;re using the following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt;: This option is used to specify the hostname. We&amp;#39;re using the hostname &lt;code&gt;127.0.0.1&lt;/code&gt;, which is the IP address for localhost.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-P&lt;/code&gt;: This option is used to specify the port. We&amp;#39;re using port &lt;code&gt;33060&lt;/code&gt;, which is the default port for MySQL.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt;: This option is used to specify the username. We&amp;#39;re using the username &lt;code&gt;mkabumattar&lt;/code&gt; in this example.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt;: This option is used to prompt for a password.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you run this command, you&amp;#39;ll be prompted to enter the password for the user. Enter the password &lt;code&gt;121612&lt;/code&gt; and hit Enter. You should then be connected to the MySQL container and be able to run SQL commands.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0040-how-to-run-mysql-in-a-docker-container-a-step-by-step-guide-with-customization-tips/connecting-to-mysql-container.png&quot; alt=&quot;Connecting to a MySQL Container&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Step 3: Customizing the MySQL Container Configuration&lt;/h3&gt;
&lt;p&gt;By default, the MySQL container uses a set of default configuration options that may not suit your needs. You can customize the configuration by creating a custom my.cnf file and mounting it into the container.&lt;/p&gt;
&lt;p&gt;To do this, you&amp;#39;ll need to create a new directory on your host system that will be used to store the custom configuration file. Next, create a my.cnf file in that directory with the desired configuration options.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example directory structure for a custom configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;/path/to/config
  |- my.cnf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the my.cnf file might contain the following configuration options:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;[mysqld]
character-set-server=utf8mb4
max_allowed_packet=64M
innodb_log_file_size=256M
innodb_buffer_pool_size=1G
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, when you run the &lt;code&gt;docker run&lt;/code&gt; command, use the -v option to mount the custom configuration directory into the container. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run --name mysql -e MYSQL_ROOT_PASSWORD=121612 -v /path/to/config:/etc/mysql/conf.d -p 33060:3306 -d mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we&amp;#39;re mounting the &lt;code&gt;/path/to/config&lt;/code&gt; directory into the &lt;code&gt;/etc/mysql/conf.d&lt;/code&gt; directory in the container. This means that the custom &lt;code&gt;my.cnf&lt;/code&gt; file will be used instead of the default configuration file.&lt;/p&gt;
&lt;p&gt;After running the container with the custom configuration, you can verify that the new options are in effect by connecting to the container and running the &lt;code&gt;SHOW VARIABLES&lt;/code&gt; command. This command will show all of the current MySQL configuration options, and you should see your custom options listed.&lt;/p&gt;
&lt;h3&gt;Step 4: Persisting Data with Docker Volumes&lt;/h3&gt;
&lt;p&gt;By default, the data stored in a Docker container is ephemeral, which means that it is not persisted across container restarts. This can be a problem if you need to keep your data intact even if the container is stopped or recreated.&lt;/p&gt;
&lt;p&gt;To persist the data, you can use Docker volumes to store the data outside of the container. Docker volumes are mappings from a directory on the host system to a directory in the container, and the data stored in the volume is not deleted when the container is deleted.&lt;/p&gt;
&lt;p&gt;To create a Docker volume, use the -v option in the docker run command and specify the mapping between the host directory and the container directory. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run --name mysql -e MYSQL_ROOT_PASSWORD=121612 -v /path/to/data:/var/lib/mysql -p 3306:3306 -d mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the &lt;code&gt;/path/to/data&lt;/code&gt; directory on the host system is mapped to the &lt;code&gt;/var/lib/mysql&lt;/code&gt; directory in the container. This means that any data stored in the &lt;code&gt;/var/lib/mysql&lt;/code&gt; directory in the container will be persisted in the &lt;code&gt;/path/to/data&lt;/code&gt; directory on the host system.&lt;/p&gt;
&lt;p&gt;Once the volume is created, you can use the &lt;code&gt;docker inspect&lt;/code&gt; command to verify that the volume has been created and that the data is being stored in the specified location on the host system.&lt;/p&gt;
&lt;p&gt;By using volumes to persist data, you can ensure that your data is safe even if the container is deleted or recreated. Additionally, if you need to upgrade the MySQL image or change the configuration, you can simply stop the container, delete it, and recreate it with the new image or configuration, while keeping your data intact.&lt;/p&gt;
&lt;h3&gt;Step 5: Stopping and Starting the MySQL Container&lt;/h3&gt;
&lt;p&gt;To stop the MySQL container, use the &lt;code&gt;docker stop&lt;/code&gt; command. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker stop mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To start the MySQL container, use the &lt;code&gt;docker start&lt;/code&gt; command. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker start mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Setting up the compose.yml File&lt;/h2&gt;
&lt;p&gt;If you want to run multiple containers, you can use the compose.yml file to define and run your application. The compose.yml file is a YAML file that defines the services that make up your application. Each service is defined using a set of configuration options that tell Docker how to run the container.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example compose.yml file that defines a MySQL container:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;version: &amp;#39;3.1&amp;#39;

x-common-variables: &amp;amp;common-variables
  MYSQL_ROOT_PASSWORD: 121612
  MYSQL_DATABASE: mydb
  MYSQL_USER: mkabumattar
  MYSQL_PASSWORD: 121612

services:
  mysql:
    image: mysql:latest
    container_name: mysql
    ports:
      - 33060:3306
    volumes:
      - /path/to/data:/var/lib/mysql
    environment:
      &amp;lt;&amp;lt;: *common-variables
      MYSQL_ROOT_PASSWORD: MYSQL_ROOT_PASSWORD
      MYSQL_HOST: localhost

  adminer:
    image: adminer
    container_name: adminer
    ports:
      - 8888:8080
    environment:
      &amp;lt;&amp;lt;: *common-variables
      ADMINER_DEFAULT_SERVER: mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we&amp;#39;re defining two services: &lt;code&gt;mysql&lt;/code&gt; and &lt;code&gt;adminer&lt;/code&gt;. The &lt;code&gt;mysql&lt;/code&gt; service defines a MySQL container, and the &lt;code&gt;adminer&lt;/code&gt; service defines an Adminer container. Adminer is a web-based database management tool that can be used to manage MySQL databases.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;mysql&lt;/code&gt; service defines the following configuration options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;image&lt;/code&gt;: The image to use to create the container. In this case, we&amp;#39;re using the &lt;code&gt;mysql:latest&lt;/code&gt; image.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;container_name&lt;/code&gt;: The name of the container. In this case, we&amp;#39;re using the name &lt;code&gt;mysql&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ports&lt;/code&gt;: The port mappings between the host system and the container. In this case, we&amp;#39;re mapping the port 33060 on the host system to the port 3306 in the container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;volumes&lt;/code&gt;: The volume mappings between the host system and the container. In this case, we&amp;#39;re mapping the &lt;code&gt;/path/to/data&lt;/code&gt; directory on the host system to the &lt;code&gt;/var/lib/mysql&lt;/code&gt; directory in the container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;environment&lt;/code&gt;: The environment variables to set in the container. In this case, we&amp;#39;re setting the &lt;code&gt;MYSQL_ROOT_PASSWORD&lt;/code&gt; environment variable to &lt;code&gt;121612&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;adminer&lt;/code&gt; service defines the following configuration options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;image&lt;/code&gt;: The image to use to create the container. In this case, we&amp;#39;re using the &lt;code&gt;adminer&lt;/code&gt; image.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;container_name&lt;/code&gt;: The name of the container. In this case, we&amp;#39;re using the name &lt;code&gt;adminer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ports&lt;/code&gt;: The port mappings between the host system and the container. In this case, we&amp;#39;re mapping the port 8080 on the host system to the port 8080 in the container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;environment&lt;/code&gt;: The environment variables to set in the container. In this case, we&amp;#39;re setting the &lt;code&gt;MYSQL_ROOT_PASSWORD&lt;/code&gt; environment variable to &lt;code&gt;121612&lt;/code&gt;, and the &lt;code&gt;ADMINER_DEFAULT_SERVER&lt;/code&gt; environment variable to &lt;code&gt;mysql&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To run the application defined in the compose.yml file, use the &lt;code&gt;docker-compose up&lt;/code&gt; command. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;-d&lt;/code&gt; option tells Docker to run the containers in the background. If you don&amp;#39;t use the &lt;code&gt;-d&lt;/code&gt; option, Docker will run the containers in the foreground and will not return control to the terminal until you stop the containers.&lt;/p&gt;
&lt;p&gt;To stop the containers, use the &lt;code&gt;docker-compose down&lt;/code&gt; command. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker-compose down
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Docker is a powerful tool that makes it easy to run and manage applications in containers. Running MySQL in a Docker container is a convenient way to isolate the database from the host system and other containers, while still having the ability to access it from other applications.&lt;/p&gt;
&lt;p&gt;In this article, we have shown you how to run a MySQL container using the &lt;code&gt;docker run&lt;/code&gt; command, connect to the container, customize the configuration, and persist the data using Docker volumes. By following these steps, you can easily run a MySQL database in a Docker container, and customize it to meet your needs.&lt;/p&gt;
&lt;p&gt;Whether you are a developer, a DevOps engineer, or a database administrator, using Docker to run MySQL can simplify your workflow and help you manage your database infrastructure more efficiently. So, why not give it a try and see for yourself?&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/get-started&quot;&gt;Docker Official Website - Get Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/_/mysql&quot;&gt;MySQL Official Docker Image - Docker Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/&quot;&gt;MySQL Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/run/&quot;&gt;Docker Run Command Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/storage/volumes/&quot;&gt;Manage data in Docker - Docker Volumes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/mysql-commands.html&quot;&gt;MySQL Client Commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/server-configuration-defaults.html&quot;&gt;MySQL Server Configuration Defaults&lt;/a&gt; (for &lt;code&gt;my.cnf&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/_/adminer&quot;&gt;Adminer Official Docker Image - Docker Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;How To Install Docker On Linux In 4 Easy Steps!&amp;quot; (Your previous article) - &lt;a href=&quot;/blog/how-to-install-docker-on-linux-in-4-easy-steps&quot;&gt;/blog/how-to-install-docker-on-linux-in-4-easy-steps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Persisting Data in Docker: A Deep Dive into Volumes&amp;quot; - (Example: Search for articles on Docker data persistence.), [Link to a relevant article]&lt;/li&gt;
&lt;li&gt;&amp;quot;Customizing MySQL Configuration in Docker&amp;quot; - (Example: Search for tutorials on this topic.), [Link to a relevant tutorial]&lt;/li&gt;
&lt;li&gt;&amp;quot;Docker Networking Basics&amp;quot; - (Example: Article from Docker&amp;#39;s documentation or a reputable blog.), [Link to a relevant article]&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Docker</category><category>MySQL</category><category>Databases</category><category>DevOps</category><category>Containerization</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0040-how-to-run-mysql-in-a-docker-container-a-step-by-step-guide-with-customization-tips/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Install Docker On Linux In 4 Easy Steps!</title><link>https://mkabumattar.com/blog/post/how-to-install-docker-on-linux-in-4-easy-steps/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-install-docker-on-linux-in-4-easy-steps/</guid><description>This article guides you through the simple process of installing Docker on Linux in 4 easy steps. From updating the package index to running your first Docker container, you&apos;ll learn everything you need to get started with this powerful platform. By the end, you&apos;ll be able to take advantage of all the benefits Docker has to offer.</description><pubDate>Sun, 12 Feb 2023 11:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Docker is a powerful platform that allows developers to create, deploy, and run applications in containers. Containers are isolated environments that allow you to run your applications in a consistent and reproducible way, no matter what platform or environment you&amp;#39;re using. With Docker, you can easily move your applications from one platform to another, making it a popular choice for developers and DevOps teams alike.&lt;/p&gt;
&lt;p&gt;Whether you&amp;#39;re building a new application or need to modernize an existing one, Docker provides a simple and efficient way to manage your applications and infrastructure. In this article, you&amp;#39;ll learn how to install Docker on Linux in just 4 easy steps. By the end, you&amp;#39;ll be up and running with Docker and ready to start using it to create and manage your applications.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before you can install Docker on Linux, there are a few prerequisites you need to be aware of. Firstly, you need to have a Linux machine that meets the minimum system requirements for running Docker. Docker requires a 64-bit operating system and a version of the Linux kernel that is 3.10 or later. You can check your Linux version by running the following command in your terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# check your Linux version
uname -r
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, you&amp;#39;ll need to have the appropriate permissions to install software on your Linux machine. If you&amp;#39;re logged in as a regular user, you may need to use &lt;code&gt;sudo&lt;/code&gt; to install Docker.&lt;/p&gt;
&lt;p&gt;Another important consideration is the type of Linux distribution you&amp;#39;re using. Docker provides native packages for several popular Linux distributions, including Debian, Ubuntu, Fedora, and CentOS. You&amp;#39;ll want to make sure you&amp;#39;re using one of these supported distributions before you start the installation process.&lt;/p&gt;
&lt;p&gt;Once you&amp;#39;ve confirmed that your Linux machine meets the prerequisites, you&amp;#39;re ready to move on to the next step and start installing Docker.&lt;/p&gt;
&lt;h2&gt;Installing Docker&lt;/h2&gt;
&lt;h3&gt;Step 1: Update the Package Index&lt;/h3&gt;
&lt;p&gt;The first step in installing Docker on Linux is to update the package index. This ensures that you have the most recent version of the Docker packages available and reduces the risk of encountering any compatibility issues.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how to update the package index on different types of Linux systems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Arch-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# update the package index
sudo pacman -Syy
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Debian-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add Docker&amp;#39;s official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  &amp;quot;deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release &amp;amp;&amp;amp; echo &amp;quot;${UBUNTU_CODENAME:-$VERSION_CODENAME}&amp;quot;) stable&amp;quot; | \
  sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
# update the package index
sudo apt-get update
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Red Hat-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# update the package index
sudo yum update
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Suse-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# update the package index
sudo zypper refresh
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Fedora-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# update the package index
sudo dnf update
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the package index has been updated, you&amp;#39;re ready to move on to the next step and start installing Docker. It&amp;#39;s a good practice to periodically update your package index, so make sure to check for updates frequently to keep your system up-to-date.&lt;/p&gt;
&lt;h3&gt;Step 2: Installing Docker on Linux using the package manager&lt;/h3&gt;
&lt;p&gt;With the package index updated, it&amp;#39;s time to install Docker on your Linux machine. This is done using the package manager for your Linux distribution.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how to install Docker on different types of Linux systems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Arch-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# install Docker
sudo pacman -S docker
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Debian-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# install Docker
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Red Hat-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# install Docker
sudo yum install docker
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Suse-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# install Docker
sudo zypper install docker
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Fedora-based Linux systems:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# install Docker
sudo dnf install docker
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the installation is complete, you can start using Docker on your Linux machine. However, there are a few more steps you need to take before you can start using Docker.&lt;/p&gt;
&lt;p&gt;Specifically, you need to start the Docker service and enable it to start automatically on boot. This ensures that Docker is always running and ready to use. Here&amp;#39;s how to start the Docker service and enable it to start automatically on boot:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# start the Docker service
sudo systemctl start docker

# enable the Docker service to start automatically on boot
sudo systemctl enable docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Verifying the Docker installation&lt;/h3&gt;
&lt;p&gt;Now that Docker is installed and running on your Linux machine, it&amp;#39;s time to verify that the installation was successful. The best way to do this is to run a simple Docker command and see if it returns the expected output.&lt;/p&gt;
&lt;p&gt;One of the simplest Docker commands you can run is the &lt;code&gt;docker info&lt;/code&gt; command. This command displays system-wide information about your Docker installation, including the number of containers and images, the version of Docker you&amp;#39;re running, and more.&lt;/p&gt;
&lt;p&gt;To run the &lt;code&gt;docker info&lt;/code&gt; command, open a terminal window and type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# run the docker info command
docker info
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the installation was successful, you should see a lot of information about your Docker installation, similar to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 19.03.13
Storage Driver: overlay2
 Operating System: Fedora 33 (Twenty Three)
 OSType: linux
 Architecture: x86_64
 CPUs: 2
 Total Memory: 7.792GiB
 Name: localhost.localdomain
 ID: &amp;lt;id&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confirms that Docker is installed and running on your Linux machine. If you encounter any errors, you may need to check the logs or consult the Docker documentation for further guidance.&lt;/p&gt;
&lt;p&gt;With Docker installed and working correctly, you&amp;#39;re ready to start creating and managing your containers. In the next step, you&amp;#39;ll learn how to use Docker to run your first container.&lt;/p&gt;
&lt;p&gt;As a security measure, Docker runs as a non-root user by default. This means that you need to add your user to the &lt;code&gt;docker&lt;/code&gt; group to be able to run Docker commands. You can do this by running the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# add your user to the docker group
sudo usermod -aG docker $USER
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Running your first Docker container&lt;/h3&gt;
&lt;p&gt;With Docker installed and verified on your Linux machine, it&amp;#39;s time to start using it to run containers. The easiest way to get started with Docker is to run a simple container, such as a &amp;quot;Hello World&amp;quot; container.&lt;/p&gt;
&lt;p&gt;To run your first Docker container, you&amp;#39;ll need to use the &lt;code&gt;docker run&lt;/code&gt; command. This command takes a Docker image and creates a new container from that image, running the commands specified in the image&amp;#39;s definition.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of how to run a &amp;quot;Hello World&amp;quot; container:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command tells Docker to run the &lt;code&gt;hello-world&lt;/code&gt; image. If you don&amp;#39;t have the &lt;code&gt;hello-world&lt;/code&gt; image on your system, Docker will automatically download it from the Docker Hub, which is a repository of Docker images.&lt;/p&gt;
&lt;p&gt;Once the container is running, you should see some output similar to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Hello from Docker!
This message shows that your installation appears to be working correctly.
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confirms that your first Docker container is up and running. You can use the &lt;code&gt;docker ps&lt;/code&gt; command to see a list of all the containers currently running on your system:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With your first Docker container running, you&amp;#39;re ready to start exploring all that Docker has to offer. You can use Docker to run any type of application, from simple single-container applications to complex multi-container applications, making it a powerful tool for building, deploying, and managing applications.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, you learned how to install Docker on Linux in 4 easy steps. With its powerful containerization technology, Docker makes it easy to run and manage applications on a variety of platforms, including Linux.&lt;/p&gt;
&lt;p&gt;By following the steps outlined in this article, you can quickly and easily install Docker on your Linux machine, verifying the installation and running your first container. From there, you can continue to explore the many features and benefits of Docker, using it to run and manage a wide range of applications and services.&lt;/p&gt;
&lt;p&gt;Whether you&amp;#39;re a software developer, system administrator, or DevOps engineer, Docker is a must-have tool for anyone looking to improve the efficiency and reliability of their application deployment and management processes. So go ahead and get started with Docker today and see what it can do for you!&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/&quot;&gt;Install Docker Engine - Official Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/ubuntu/&quot;&gt;Install Docker Engine on Ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/debian/&quot;&gt;Install Docker Engine on Debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/fedora/&quot;&gt;Install Docker Engine on Fedora&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/centos/&quot;&gt;Install Docker Engine on CentOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Docker&quot;&gt;Install Docker Engine on Arch Linux (Community Supported)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/linux-postinstall/&quot;&gt;Post-installation steps for Linux - Docker Documentation&lt;/a&gt; (Covers managing Docker as a non-root user)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/&quot;&gt;Docker Hub - Official Image Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker run&lt;/code&gt; command reference - &lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/run/&quot;&gt;Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker info&lt;/code&gt; command reference - &lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/info/&quot;&gt;Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker ps&lt;/code&gt; command reference - &lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/ps/&quot;&gt;Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;What is a Container?&amp;quot; - Docker Documentation.), &lt;a href=&quot;https://www.docker.com/resources/what-container/&quot;&gt;https://www.docker.com/resources/what-container/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Get Started with Docker&amp;quot; - Docker Documentation.), &lt;a href=&quot;https://docs.docker.com/get-started/&quot;&gt;https://docs.docker.com/get-started/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Linux &lt;code&gt;uname&lt;/code&gt; command - (Example: man page or tutorial.), &lt;a href=&quot;https://man7.org/linux/man-pages/man1/uname.1.html&quot;&gt;https://man7.org/linux/man-pages/man1/uname.1.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Linux &lt;code&gt;systemctl&lt;/code&gt; command - (Example: man page or tutorial.), &lt;a href=&quot;https://man7.org/linux/man-pages/man1/systemctl.1.html&quot;&gt;https://man7.org/linux/man-pages/man1/systemctl.1.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>Docker</category><category>Linux</category><category>DevOps</category><category>System Administration</category><category>Containerization</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0039-how-to-install-docker-on-linux-in-4-easy-steps/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Avoid Common Cloud Services Mistakes</title><link>https://mkabumattar.com/blog/post/how-to-avoid-common-cloud-services-mistakes/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-avoid-common-cloud-services-mistakes/</guid><description>This article will cover common mistakes made when implementing cloud services and offer solutions to avoid them. The introduction will explain the importance of avoiding these mistakes. The article will then discuss specific mistakes such as not fully understanding the service, not securing resources, lack of monitoring, no disaster recovery plan, vendor lock-in and lack of compliance, outdated software, scalability issues, cost concerns, lack of exit strategy, migration and backup/recovery plan. The conclusion will summarize key points and provide additional resources.</description><pubDate>Fri, 20 Jan 2023 11:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;By offering scalable, on-demand resources and services, cloud services have completely changed the way organizations operate. Implementing cloud services, however, can provide its own set of difficulties and possible blunders. Common errors including inadequate resource security, a lack of understanding of the service, and the absence of a disaster recovery strategy can result in expensive downtime, security breaches, and even data loss.&lt;/p&gt;
&lt;p&gt;Amazon Web Services is one of the most well-known suppliers of cloud services (AWS). Numerous services, including computing power, storage, databases, analytics, and more, are offered by AWS. While there are numerous advantages to using AWS, it&amp;#39;s critical for organizations to be informed of any potential drawbacks before using these services. For instance, improper S3 bucket security on AWS might result in sensitive data being made available to the public, as was the case in a number of high-profile events in the past. Additionally, the organization may incur unanticipated high expenditures as a result of failing to monitor and manage resource utilization.&lt;/p&gt;
&lt;p&gt;With a particular focus on Amazon Web Services, we will examine some of the most frequent mistakes made while establishing cloud services and provide solutions for avoiding them in this article (AWS). Businesses may guarantee a seamless and safe installation of cloud services while also reaping the numerous benefits they provide by taking the time to understand and avoid these pitfalls.&lt;/p&gt;
&lt;h2&gt;Common fatal mistakes at Cloud Services&lt;/h2&gt;
&lt;p&gt;When implementing cloud services, businesses often make mistakes that can have severe consequences. The following are some of the most common mistakes made when implementing cloud services and how to avoid them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Before implementation, businesses could not completely comprehend the capabilities and constraints of the service they are installing, which can result in worse performance, higher costs, and unanticipated downtime.&lt;/li&gt;
&lt;li&gt;Failure to effectively protect cloud resources can result in data breaches and unauthorized access. Examples of such cloud resources include virtual machines, storage, and databases.&lt;/li&gt;
&lt;li&gt;Monitoring and regulating resource utilization is important since failing to do so might result in unexpectedly significant expenditures for the company.&lt;/li&gt;
&lt;li&gt;In the case of an outage or disaster, not having a disaster recovery strategy in place might lead to data loss and protracted downtime.&lt;/li&gt;
&lt;li&gt;Businesses may find it difficult to migrate data and applications across cloud providers, which would result in a loss of control and higher costs if vendor lock-in and loss of control were taken into account.&lt;/li&gt;
&lt;li&gt;If compliance requirements are not taken into consideration, businesses may not be aware of the compliance standards that apply to their sector, which might result in non-compliance and significant legal problems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, with AWS, improper S3 bucket security can result in sensitive data being made available to the public, as was the case in a number of high-profile events in the past. Furthermore, failing to monitor and manage AWS resource utilization might result in unexpectedly large expenditures for the company. In the case of an outage or disaster, not having a disaster recovery strategy on place in AWS can lead to data loss and protracted downtime. It can be challenging to migrate data and apps across cloud providers due to vendor lock-in and loss of control with AWS.&lt;/p&gt;
&lt;p&gt;Businesses should be aware of these typical errors and take the appropriate precautions to avoid them. Businesses may guarantee a seamless and safe installation of cloud services while also reaping the numerous benefits they provide by taking the time to understand and avoid these pitfalls.&lt;/p&gt;
&lt;h3&gt;Not fully understanding the service before implementation&lt;/h3&gt;
&lt;p&gt;Not knowing a cloud service completely before to installation is one of the most frequent errors enterprises make. It may also result in unanticipated downtime, higher expenses, and worse performance. Prior to use, it&amp;#39;s crucial to thoroughly investigate and comprehend the service&amp;#39;s capabilities and constraints.&lt;/p&gt;
&lt;p&gt;For example, with AWS, a lack of scalability and availability might result from a failure to properly comprehend the capabilities and restrictions of Amazon Elastic Compute Cloud (EC2). Additionally, failing to properly comprehend Amazon Simple Storage Service&amp;#39;s (S3) capabilities and constraints might result in unexpectedly expensive costs for data storage and retrieval.&lt;/p&gt;
&lt;p&gt;Businesses should investigate and comprehend the service they intend to use, including its capabilities, limits, and cost, in order to avoid making this error. All of AWS&amp;#39;s services are covered by documentation and tutorials, and companies may use the free-tier service to test the product before committing to a complete deployment. Businesses may also seek the assistance of AWS-certified experts who have the expertise and knowledge to help them fully comprehend the service and its potential.&lt;/p&gt;
&lt;p&gt;In order to prevent unforeseen problems and expenses, it is crucial for organizations to take the time to understand the service they intend to deploy. Businesses may guarantee a seamless and effective installation of cloud services by properly knowing the service.&lt;/p&gt;
&lt;h3&gt;Failing to properly secure cloud resources&lt;/h3&gt;
&lt;p&gt;Implementing cloud services without properly securing cloud resources is another error that enterprises make frequently. Insufficiently protecting cloud resources like virtual machines, storage, and databases can result in data breaches and unauthorized access.&lt;/p&gt;
&lt;p&gt;Businesses should take the required actions to adequately protect their cloud resources in order to avoid making this error. This includes the following in AWS:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enabling encryption for data at rest and in transit&lt;/li&gt;
&lt;li&gt;Using Identity and Access Management (IAM) to control access to resources&lt;/li&gt;
&lt;li&gt;Using security groups and network access control lists (ACLs) to control inbound and outbound traffic&lt;/li&gt;
&lt;li&gt;Using a Web Application Firewall (WAF) to protect against common web attacks&lt;/li&gt;
&lt;li&gt;Regularly monitoring logs and security events&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to protect sensitive data and prevent data breaches, it is crucial for organizations to take the required precautions while securing their cloud resources. The security and integrity of a company&amp;#39;s data may be ensured by appropriately safeguarding cloud resources.&lt;/p&gt;
&lt;h3&gt;Not monitoring and managing resource usage&lt;/h3&gt;
&lt;p&gt;When installing cloud services, organizations frequently neglect to monitor and manage resource utilization. If resource utilization is not tracked and managed, organizations may unintentionally go over their allotted amounts and pay additional fees.&lt;/p&gt;
&lt;p&gt;For example, failing to manage and monitor the utilization of Amazon Elastic Compute Cloud (EC2) instances and Amazon Elastic Block Store (EBS) volumes in AWS might result in unforeseenly high expenditures from increasing consumption and data storage.&lt;/p&gt;
&lt;p&gt;Businesses should install monitoring and alerting systems to keep track of resource utilization and make sure they adhere to usage caps in order to prevent making this error. This is possible in AWS thanks to CloudWatch, which offers resource and application monitoring for AWS. Businesses may use AWS Cost Explorer to examine expenses, manage them, and find areas where costs can be reduced.&lt;/p&gt;
&lt;p&gt;To prevent unforeseen expenditures and stay within budget, it&amp;#39;s critical for businesses to monitor and control resource utilization. Businesses may make sure that they are using resources efficiently and effectively by monitoring and regulating resource utilization.&lt;/p&gt;
&lt;h3&gt;Not having a disaster recovery plan in place&lt;/h3&gt;
&lt;p&gt;Lack of a disaster recovery strategy is a typical error businesses make when utilizing cloud services. In the case of an outage or disaster, not having a disaster recovery strategy in place might lead to data loss and protracted downtime. This may result in a large loss of income and harm to a company&amp;#39;s image.&lt;/p&gt;
&lt;p&gt;For example, if an Amazon Simple Storage Service (S3) bucket or an Amazon Elastic Compute Cloud (EC2) instance fails, not having a disaster recovery strategy in place might lead to data loss and protracted downtime.&lt;/p&gt;
&lt;p&gt;To prevent making this error, businesses should create and test a disaster recovery strategy to make sure that data and applications can be swiftly restored in the case of an outage or disaster. This may be accomplished utilizing AWS services like Amazon RDS Automated Backups, Amazon Elastic Block Store (EBS) snapshots, and Amazon S3 versioning. In the case of a failure, organizations may leverage AWS services like Elastic Load Balancing and Amazon Route 53 to automatically route traffic to backup resources.&lt;/p&gt;
&lt;p&gt;To reduce the impact of an outage or disaster on their operations, businesses should have a disaster recovery strategy in place. Businesses may minimize the impact on their operations and income by having a disaster recovery strategy in place, which will allow them to swiftly restore data and apps in the case of an outage or disaster.&lt;/p&gt;
&lt;h3&gt;Not considering vendor lock-in and loss of control&lt;/h3&gt;
&lt;p&gt;Lack of consideration for vendor lock-in and loss of control is another error that enterprises make when deploying cloud services. Businesses could find it difficult to migrate their data and apps across cloud service providers, which would mean losing control and spending more money.&lt;/p&gt;
&lt;p&gt;For example, since the data and apps are unique to AWS, not taking vendor lock-in and loss of control into account might make it challenging to move data and applications between cloud providers. Additionally, companies could find themselves unable to transfer to other providers or services, even if they are more affordable or better suited to their requirements, due to being tied into certain AWS services.&lt;/p&gt;
&lt;p&gt;When deploying cloud services, businesses need to take vendor lock-in and loss of control into account to avoid making this error. Using open-source technology and established protocols will enable this and make it simpler to transfer data and applications between cloud service providers. AWS services like AWS App Runner, AWS CloudFormation, and AWS Elastic Beanstalk, which are intended to make it simpler to migrate applications across providers, as well as multi-cloud strategies, which enable companies to leverage several cloud providers, are other tools that enterprises may employ.&lt;/p&gt;
&lt;p&gt;In order to maintain control over their data and applications while deploying cloud services, enterprises must take vendor lock-in and loss of control into account. Businesses may make sure they are not tied into a particular provider or service and can quickly migrate their data and apps between cloud providers if needed by taking vendor lock-in and loss of control into consideration.&lt;/p&gt;
&lt;h3&gt;Not keeping software up to date&lt;/h3&gt;
&lt;p&gt;Maintaining outdated software is another error that businesses make when deploying cloud services. Software updates are necessary to prevent security flaws, performance difficulties, and compatibility concerns.&lt;/p&gt;
&lt;p&gt;For example, with AWS, not updating software on Amazon Elastic Compute Cloud (EC2) instances can lead to performance concerns, security risks, and challenges with interoperability with other services and applications. Additionally, accessing the AWS services may have issues if the AWS Management Console, SDKs, and other tools are not kept up to date.&lt;/p&gt;
&lt;p&gt;Businesses should make sure all software is kept up-to-date in order to prevent making this error, including operating systems, apps, and AWS management tools. Businesses may automatically patch and upgrade their EC2 instances using AWS Systems Manager, which can be used to accomplish this. Businesses may also utilize AWS Trusted Advisor, which offers suggestions on security, performance, and other best practices, to guarantee that the software is up to current.&lt;/p&gt;
&lt;p&gt;Software updates are crucial for organizations to avoid security flaws, performance concerns, and compatibility issues. Businesses may take advantage of the newest features and capabilities of cloud services by keeping their software up to date, which also guarantees system security and optimal performance.&lt;/p&gt;
&lt;h3&gt;Not paying attention to scalability needs&lt;/h3&gt;
&lt;p&gt;Businesses sometimes neglect the demands for up- and down-scalability when deploying cloud services, which is another typical error. Lack of attention to scalability requirements can lead to worse performance, higher costs, and unanticipated downtime if the resources and services are unable to handle an increase in demand or users, or adapt when usage reduces.&lt;/p&gt;
&lt;p&gt;For example, in AWS, failing to consider scalability requirements when using Amazon Relational Database Service (RDS) or Amazon Elastic Compute Cloud (EC2) can lead to subpar performance, higher costs, and unanticipated downtime as the resources and services may not be able to handle an increase in users or demand or to adapt when usage declines.&lt;/p&gt;
&lt;p&gt;When establishing cloud services, businesses should be mindful of the requirement for scalability, especially scalability up and down, to avoid making this error. This may be accomplished in AWS utilizing AWS Auto Scaling, which automatically scales the number of Amazon EC2 instances depending on demand, and Amazon RDS, which scales the number of read replicas based on load. Businesses may also make advantage of AWS Elastic Load Balancing, which automatically splits incoming traffic among many Amazon EC2 instances. Businesses may use AWS Auto Scaling rules to alter the number of instances based on CloudWatch measurements as needed, schedule scaling activities, and use the AWS Cost Explorer to find cost-saving opportunities.&lt;/p&gt;
&lt;p&gt;When implementing cloud services, it&amp;#39;s critical for organizations to pay attention to scalability requirements, both up and down, to make sure that resources and services can support a rising user base or greater demand and also adjust when usage lowers. Businesses may make sure that their systems are able to manage the load, provide a pleasant user experience, and save excessive expenditures by paying attention to scalability demands, both up and down. In order to keep their scaling plans consistent with the most recent use and demand trends, businesses should also periodically examine and modify them. CloudWatch, AWS Auto Scaling, and AWS Cost Explorer are just a few of the tools that AWS offers to assist organizations in tracking and managing their scalability requirements, both up and down.&lt;/p&gt;
&lt;h3&gt;Not considering the cost of the service&lt;/h3&gt;
&lt;p&gt;When using cloud services, businesses frequently neglect to take the cost of the service into account. When the cost of the service is not taken into account, the firm may incur unforeseen high expenditures and find it challenging to stay within its budget.&lt;/p&gt;
&lt;p&gt;For example, with AWS, ignoring the pricing of services like Amazon Relational Database Service (RDS), Amazon Simple Storage Service (S3), and Amazon Elastic Compute Cloud (EC2) might result in unforeseenly large expenses for the company as use rises and data storage needs expand.&lt;/p&gt;
&lt;p&gt;When implementing cloud services, organizations should take into account the cost of the service to avoid making this error. The AWS Cost Explorer, which enables companies to analyze and control expenses and assists in identifying areas where costs may be minimized, can be used to accomplish this in AWS. Additionally, companies may estimate the cost of various services using the AWS Simple Monthly Calculator and compare prices of various services using the &lt;a href=&quot;https://calculator.aws/#/&quot;&gt;AWS Pricing page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When using cloud services, it&amp;#39;s critical for organizations to take into account the cost of the service to prevent unforeseen high expenditures and maintain budgetary constraints. Businesses can guarantee that they are using resources effectively and efficiently by taking into account the cost of the service, and they can also make educated decisions about how to use cloud services.&lt;/p&gt;
&lt;h3&gt;Not having a proper backup and recovery strategy&lt;/h3&gt;
&lt;p&gt;Lack of a comprehensive backup and recovery strategy is another typical error businesses make when utilizing cloud services. In the case of an outage or disaster, not having a robust backup and recovery plan might cause data loss and prolonged downtime.&lt;/p&gt;
&lt;p&gt;For example, in the case of an Amazon Simple Storage Service (S3) bucket failure or an Amazon Elastic Compute Cloud (EC2) instance failure, failing to have a robust backup and recovery plan may result in data loss and prolonged downtime. In the case of an outage or disaster, it may also be challenging to restore data and apps if you don&amp;#39;t have a suitable backup and recovery plan.&lt;/p&gt;
&lt;p&gt;To prevent making this mistake, companies should develop and test a backup and recovery strategy to guarantee that data and applications can be swiftly restored in the case of an outage or disaster. This is possible with AWS&amp;#39;s Elastic Block Store (EBS) snapshots, Amazon S3 versioning, and Amazon RDS Automated Backups services. Companies may also utilize AWS Backup, a single tool that makes it simple to automate backups across several AWS services.&lt;/p&gt;
&lt;p&gt;To reduce the impact of an outage or disaster on their operations, businesses should have an effective backup and recovery plan in place. Businesses may minimize the impact on their operations and income by putting in place an effective backup and recovery plan that will allow them to swiftly restore data and apps in the event of an outage or disaster.&lt;/p&gt;
&lt;h3&gt;Not having a proper exit strategy&lt;/h3&gt;
&lt;p&gt;Lack of a clear exit strategy is another typical error businesses make when deploying cloud services. When it comes time to stop using the cloud service or switch to an other provider, not having a good exit strategy might cause problems and extra expenditures.&lt;/p&gt;
&lt;p&gt;For example, failing to have a solid exit plan in AWS might make it more difficult and expensive to stop using the service or switch to an other provider. Costs for data transfer, resource and application reconfiguration, and the requirement to buy new licenses or services might all fall under this category.&lt;/p&gt;
&lt;p&gt;When deploying cloud services, businesses should have a suitable exit strategy in place to prevent making this error. This may be achieved by routinely reexamining and revising the departure plan, taking into account aspects like data migration, resource reconfiguration, and the requirement to buy new licenses or services, among others. Businesses may also employ multi-cloud strategies, which enable them to leverage several cloud providers, as well as AWS technologies like AWS App Runner, AWS CloudFormation, and AWS Elastic Beanstalk, which are meant to make it simpler to migrate applications across providers.&lt;/p&gt;
&lt;p&gt;When implementing cloud services, it&amp;#39;s crucial for organizations to have a solid exit plan in place to make sure the process of stopping usage of the service or switching to a different provider is simple and affordable. Businesses can guarantee that they are ready for any situation and can make educated decisions about how to use cloud services by having a suitable exit strategy in place.&lt;/p&gt;
&lt;h3&gt;Not having a proper migration plan&lt;/h3&gt;
&lt;p&gt;Lack of a good migration strategy is another typical error businesses make when utilizing cloud services. When moving data and apps to the cloud, not having a comprehensive migration plan might cause problems and increase expenses.&lt;/p&gt;
&lt;p&gt;Without a suitable migration strategy, moving data and apps to the cloud via AWS, for instance, may be challenging and expensive. Costs for data transfer, resource and application reconfiguration, and the requirement to buy new licenses or services might all fall under this category. Inadequate migration planning can also result in compatibility, security, and performance problems both during and after the migration process.&lt;/p&gt;
&lt;p&gt;When using cloud services, businesses should have a thorough migration strategy in place to prevent making this error. To do this, it is necessary to evaluate the data and applications&amp;#39; existing state, establish the desired state, and develop a thorough strategy for moving the data and apps to the cloud. AWS services that are intended to aid in the migration process, such as the AWS Migration Hub, the AWS Server Migration Service, and the AWS Application Discovery Service, are also available to enterprises.&lt;/p&gt;
&lt;p&gt;When deploying cloud services, it&amp;#39;s crucial for organizations to have a solid migration strategy in place to make sure the transfer of data and apps is easy and affordable. Businesses can guarantee they are ready for any situation and can make educated decisions regarding their migration to cloud services by having a solid migration strategy in place.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;With such a host of advantages including scalability, dependability, and affordability, cloud services have emerged as a crucial component of contemporary corporate operations. Implementing cloud services, however, can also present a unique set of difficulties and errors. The most typical mistakes are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Not fully understanding the service before implementation&lt;/li&gt;
&lt;li&gt;Failing to properly secure cloud resources&lt;/li&gt;
&lt;li&gt;Not monitoring and managing resource usage&lt;/li&gt;
&lt;li&gt;Not having a disaster recovery plan in place&lt;/li&gt;
&lt;li&gt;Not considering vendor lock-in and loss of control&lt;/li&gt;
&lt;li&gt;Not keeping software up to date&lt;/li&gt;
&lt;li&gt;Not paying attention to scalability needs&lt;/li&gt;
&lt;li&gt;Not considering the cost of the service&lt;/li&gt;
&lt;li&gt;Not having a proper backup and recovery strategy&lt;/li&gt;
&lt;li&gt;Not having a proper exit strategy&lt;/li&gt;
&lt;li&gt;Not having a proper migration plan&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To prevent these mistakes, businesses should thoroughly research and comprehend the cloud services they are considering, properly secure their resources, monitor and manage resource usage, have a disaster recovery plan in place, consider vendor lock-in and loss of control, take into account compliance requirements, keep software up to date, pay attention to scalability needs (both up and down), consider the cost of the service, have a proper exit strategy, have a proper backup and restore procedure, and keep software up to date.&lt;/p&gt;
&lt;p&gt;The crucial thing to remember is that these blunders and how to prevent them are not exclusive to AWS; they also apply to other cloud service providers like Azure and GCP, so organizations should bear this in mind when installing cloud services on any platform. Businesses can make sure they are utilizing their cloud services to their full potential and can function with confidence by avoiding these frequent blunders.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;AWS Well-Architected Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://d1.awsstatic.com/whitepapers/Security/AWS_Security_Best_Practices.pdf&quot;&gt;AWS Security Best Practices Whitepaper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/professional-services/CAF/&quot;&gt;AWS Cloud Adoption Framework (CAF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/aws-cost-management/&quot;&gt;AWS Cost Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/aws-cost-management/aws-cost-explorer/&quot;&gt;AWS Cost Explorer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/backup/&quot;&gt;AWS Backup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/disaster-recovery/&quot;&gt;Disaster Recovery on AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/migration-hub/&quot;&gt;AWS Migration Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html&quot;&gt;AWS Identity and Access Management (IAM) Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/security-best-practices.html&quot;&gt;Amazon S3 Security Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-patch.html&quot;&gt;AWS Systems Manager Patch Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/autoscaling/&quot;&gt;AWS Auto Scaling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/premiumsupport/technology/trusted-advisor/&quot;&gt;AWS Trusted Advisor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/compliance/&quot;&gt;AWS Compliance Center&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/cloudformation/&quot;&gt;AWS CloudFormation&lt;/a&gt; (For managing infrastructure and avoiding vendor lock-in to some extent)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Cloud Strategy</category><category>AWS</category><category>Cloud Security</category><category>Cost Management</category><category>DevOps</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0038-how-to-avoid-common-cloud-services-mistakes/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Deploy a Spring Boot Application to AWS CloudFormation</title><link>https://mkabumattar.com/blog/post/how-to-deploy-a-spring-boot-application-to-aws-cloudformation/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-deploy-a-spring-boot-application-to-aws-cloudformation/</guid><description>This article will guide you on how to deploy a Spring Boot application to AWS CloudFormation. It covers steps from creating a CloudFormation template, packaging the application into a deployable artifact, updating the stack with the new version of the application and discussing about continuous deployment for automatic updates. This guide is intended for developers who have an existing Spring Boot application and want to deploy it on AWS.</description><pubDate>Tue, 17 Jan 2023 11:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Deploying a Spring Boot application to the cloud can provide many benefits such as scalability and easy management. AWS CloudFormation is a service that allows for the creation and management of infrastructure as code, making it easy to provision and update resources. In this article, we will go over the steps to deploy a Spring Boot application to AWS CloudFormation. We will cover how to create a CloudFormation template, package the application into a deployable artifact, update the stack with the new version of the application, and set up continuous deployment to automatically update the application when new code is pushed to a version control repository. By the end of this guide, you will have a solid understanding of how to deploy a Spring Boot application to AWS CloudFormation.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;A few requirements must be satisfied before beginning to deploy a Spring Boot application to AWS CloudFormation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An AWS account is required to use AWS CloudFormation.&lt;/li&gt;
&lt;li&gt;The Spring Boot application should be already built and ready for deployment.&lt;/li&gt;
&lt;li&gt;Familiarity with AWS CloudFormation and the AWS Management Console is recommended.&lt;/li&gt;
&lt;li&gt;AWS CLI and AWS SDK should be installed in the local machine.&lt;/li&gt;
&lt;li&gt;AWS IAM user with permissions to create and update CloudFormation stacks.&lt;/li&gt;
&lt;li&gt;Familiarity with the Spring Boot application&amp;#39;s dependencies and configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before starting the deployment process, make sure you have met all the requirements.&lt;/p&gt;
&lt;h2&gt;Creating a CloudFormation template&lt;/h2&gt;
&lt;h3&gt;What is a CloudFormation template?&lt;/h3&gt;
&lt;p&gt;AWS CloudFormation is a tool that enables you to model and provide all the resources required for your applications across all of your AWS accounts and locations in an automated and secure way using a single YAML or JSON file. Known as a CloudFormation template, this file.&lt;/p&gt;
&lt;p&gt;All the AWS resources you wish to generate and configure for your application, together with their interdependencies, are listed in a CloudFormation template. The template is a text file with JSON or YAML formatting. You may use this straightforward, reusable, and simple-to-read framework to represent your infrastructure. To create, edit, and delete stacks using CloudFormation templates, utilize the AWS Management Console, AWS Command Line Interface (CLI), or SDKs.&lt;/p&gt;
&lt;p&gt;A potent tool that enables you to design your infrastructure as code is the CloudFormation template. This implies that you may test your templates in various settings, version control them, and undo changes as needed. You may automate the construction and administration of your resources with CloudFormation, which can save you time and lower the possibility of human mistake.&lt;/p&gt;
&lt;h3&gt;Creating the template&lt;/h3&gt;
&lt;p&gt;You may create a CloudFormation template in one of three ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From Scratch&lt;/li&gt;
&lt;li&gt;Using one of the sample templates provided by AWS CloudFormation&lt;/li&gt;
&lt;li&gt;Using the AWS CloudFormation Designer&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;From Scratch&lt;/h4&gt;
&lt;p&gt;You can create a template by hand using a text editor. You can use either JSON or YAML to write the template, however, YAML is more human-readable and less verbose.&lt;/p&gt;
&lt;h4&gt;Using one of the sample templates provided by AWS CloudFormation&lt;/h4&gt;
&lt;p&gt;AWS CloudFormation provides a number of sample templates that cover different scenarios and use cases. You can use these templates as a starting point and customize them to suit your needs.&lt;/p&gt;
&lt;h4&gt;Using the AWS CloudFormation Designer&lt;/h4&gt;
&lt;p&gt;The AWS CloudFormation Designer is a visual editor that allows you to create a CloudFormation template by dragging and dropping resources. You can use the AWS CloudFormation Designer to create a template for a simple application, but it is not recommended for more complex applications.&lt;/p&gt;
&lt;h3&gt;Template structure&lt;/h3&gt;
&lt;p&gt;Six primary parts make up a CloudFormation template:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;AWSTemplateFormatVersion&amp;quot;&lt;/strong&gt;: This field is required and specifies the format version of the CloudFormation template. The current version is &amp;quot;2010-09-09&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Description&amp;quot;&lt;/strong&gt;: This field is optional and provides a brief description of the stack and its resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Metadata&amp;quot;&lt;/strong&gt;: This field is optional and provides additional information about the template and its resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Parameters&amp;quot;&lt;/strong&gt;: This field is optional and allows you to pass input values to the template at runtime. This allows you to customize the stack&amp;#39;s resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Resources&amp;quot;&lt;/strong&gt;: This field is required and defines the stack&amp;#39;s resources and their properties.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Outputs&amp;quot;&lt;/strong&gt;: This field is optional and allows you to output values from the stack&amp;#39;s resources. This can be useful for displaying information about the stack&amp;#39;s resources after it is created.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Understanding a CloudFormation template&amp;#39;s structure and the many elements it consists of is crucial since doing so will make it easier for you to develop and alter your templates.&lt;/p&gt;
&lt;h3&gt;Creating a CloudFormation template for a Spring Boot application&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ll build a CloudFormation template for a Spring Boot application in this part. Although we will start from scratch, you are free to apply any of the techniques mentioned in the previous section. The template will deploy the Spring Boot application, set up Java, and establish an EC2 instance. To increase the application&amp;#39;s scalability and fault tolerance, you may utilize advanced AWS services like a load balancer, auto-scaling groups, and others.&lt;/p&gt;
&lt;h4&gt;Template structure&lt;/h4&gt;
&lt;p&gt;The template will consist of the following sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWSTemplateFormatVersion&lt;/li&gt;
&lt;li&gt;Description&lt;/li&gt;
&lt;li&gt;Parameters&lt;/li&gt;
&lt;li&gt;Metadata&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;li&gt;Outputs&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;AWSTemplateFormatVersion&lt;/h4&gt;
&lt;p&gt;The first section of the template is the AWSTemplateFormatVersion section. This section is required and specifies the format version of the CloudFormation template. The current version is &amp;quot;2010-09-09&amp;quot;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;AWSTemplateFormatVersion: 2010-09-09
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Description&lt;/h4&gt;
&lt;p&gt;The next section is the Description section. This section is optional and provides a brief description of the stack and its resources.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;Description: &amp;gt;-
  This template deploys a Spring Boot application to AWS CloudFormation.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Parameters&lt;/h4&gt;
&lt;p&gt;The next section is the Parameters section. This section is optional and allows you to pass input values to the template at runtime. This allows you to customize the stack&amp;#39;s resources.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;Parameters:
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - t3.nano
      - t3.micro
      - t3.small
      - t3.medium
      - t3.large
      - t3.xlarge
      - t3.2xlarge
      - m1.small
      - m1.medium
      - m1.large
      - m1.xlarge
      - m2.xlarge
      - m2.2xlarge
      - m2.4xlarge
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - m4.16xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
      - m5.12xlarge
      - m5.24xlarge
      - m5d.large
      - m5d.xlarge
      - m5d.2xlarge
      - m5d.4xlarge
      - m5d.12xlarge
      - m5d.24xlarge
      - c1.medium
      - c1.xlarge
      - c3.large
      - c3.xlarge
      - c3.2xlarge
      - c3.4xlarge
      - c3.8xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5.9xlarge
    ConstraintDescription: must be a valid EC2 instance type.
  AMI:
    Description: &amp;gt;-
      The ID of the Amazon Machine Image (AMI) that you want to use to launch
      the instances.
    Type: AWS::SSM::Parameter::Value&amp;lt;AWS::EC2::Image::Id&amp;gt;
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The template contains three parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;KeyName: This parameter specifies the name of an existing EC2 KeyPair to enable SSH access to the instance.&lt;/li&gt;
&lt;li&gt;InstanceType: This parameter specifies the EC2 instance type.&lt;/li&gt;
&lt;li&gt;AMI: This parameter specifies the ID of the Amazon Machine Image (AMI) that you want to use to launch the instances.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Metadata&lt;/h4&gt;
&lt;p&gt;The next section is the Metadata section. This section is optional and provides additional information about the template and its resources.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: EC2 Instance Configuration
        Parameters:
          - KeyName
          - InstanceType
          - AMI
    ParameterLabels:
      KeyName:
        default: EC2 Key Pair
      InstanceType:
        default: EC2 Instance Type
      AMI:
        default: Amazon Machine Image (AMI)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Resources&lt;/h4&gt;
&lt;p&gt;The next section is the Resources section. This section is required and defines the stack&amp;#39;s resources and their properties.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 15.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-VPC

  PublicSubnet:
    Type: AWS::EC2::Subnet
    DependsOn:
      - VPC
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 15.0.0.0/24
      AvailabilityZone: !Select [0, !GetAZs &amp;#39;&amp;#39;]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-PublicSubnet

  IGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-IGW
  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    DependsOn:
      - VPC
      - IGW
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref IGW

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn:
      - VPC
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-PublicRouteTable

  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref IGW

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    DependsOn:
      - PublicRouteTable
      - PublicSubnet
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  SpringBootSG:
    Type: AWS::EC2::SecurityGroup
    DependsOn:
      - VPC
    Properties:
      GroupDescription: Security group for Spring Boot application
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-SpringBootSG

  S3CodeBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Join
        - &amp;#39;-&amp;#39;
        - - code-bucket
          - !Ref AWS::Region
          - !Select
            - 0
            - !Split
              - &amp;#39;-&amp;#39;
              - !Select
                - 2
                - !Split
                  - &amp;#39;/&amp;#39;
                  - !Ref &amp;#39;AWS::StackId&amp;#39;
      AccessControl: Private
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-S3CodeBucket

  SprerBootEC2:
    Type: AWS::EC2::Instance
    DependsOn:
      - SpringBootSG
      - PublicSubnet
    Properties:
      ImageId: !Ref AMI
      InstanceType: !Ref InstanceType
      KeyName: !Ref KeyName
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet:
            - !Ref SpringBootSG
          SubnetId: !Ref PublicSubnet
      UserData:
        Fn::Base64: !Sub
          - |
            #!/bin/bash
            sudo yum update -y
            sudo amazon-linux-extras enable java-openjdk11 -y
            sudo amazon-linux-extras install java-openjdk11 -y
            sudo yum install -y java-11-openjdk-devel
          - {}
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-SpringBootEC2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The template contains the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VPC: This resource creates a VPC with a CIDR block of &lt;code&gt;15.0.0.0/16&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;PublicSubnet: This resource creates a public subnet with a CIDR block of &lt;code&gt;15.0.0.0/24&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;IGW: This resource creates an Internet Gateway.&lt;/li&gt;
&lt;li&gt;VPCGatewayAttachment: This resource attaches the Internet Gateway to the VPC.&lt;/li&gt;
&lt;li&gt;PublicRouteTable: This resource creates a public route table.&lt;/li&gt;
&lt;li&gt;PublicRoute: This resource creates a public route.&lt;/li&gt;
&lt;li&gt;PublicSubnetRouteTableAssociation: This resource associates the public route table with the public subnet.&lt;/li&gt;
&lt;li&gt;SpringBootSG: This resource creates a security group for the Spring Boot application.&lt;/li&gt;
&lt;li&gt;S3CodeBucket: This resource creates an S3 bucket to store the Spring Boot application code.&lt;/li&gt;
&lt;li&gt;SprerBootEC2: This resource creates an EC2 instance to host the Spring Boot application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Outputs&lt;/h4&gt;
&lt;p&gt;The next section is the Outputs section. This section is optional and provides information about the stack&amp;#39;s resources.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;Outputs:
  S3CodeBucket:
    Description: S3 bucket to store the Spring Boot application code
    Value: !Ref S3CodeBucket
  SpringBootEC2:
    Description: Spring Boot EC2 instance
    Value: !Ref SprerBootEC2
  SpringBootEC2PublicIP:
    Description: Spring Boot EC2 instance public IP
    Value: !GetAtt SprerBootEC2.PublicIp
  SpringBootEC2PublicDNS:
    Description: Spring Boot EC2 instance public DNS
    Value: !GetAtt SprerBootEC2.PublicDnsName
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The template contains the following outputs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;S3CodeBucket: This output provides the S3 bucket name to store the Spring Boot application code.&lt;/li&gt;
&lt;li&gt;SpringBootEC2IP: This output provides the IP address of the Spring Boot EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To get the full template, see &lt;a href=&quot;/code/blog/0037-how-to-deploy-a-spring-boot-application-to-aws-cloudformation/spring-boot-cloudformation-template-cfn.yaml&quot;&gt;&lt;code&gt;spring-boot-cloudformation-template-cfn.yaml&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Create the Stack&lt;/h3&gt;
&lt;p&gt;To create a stack using a CloudFormation template, you can use the AWS Management Console, AWS CLI, or SDKs. Here&amp;#39;s an example of how to create a stack using the AWS CLI:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws cloudformation create-stack \
  --stack-name spring-boot-cloudformation \
  --template-body file://spring-boot-cloudformation-template-cfn.yaml \
  --parameters ParameterKey=KeyName,ParameterValue=aws-key-pair \
  --capabilities CAPABILITY_NAMED_IAM
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command creates a stack:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--stack-name&lt;/code&gt;: The name of the stack, which is &lt;code&gt;spring-boot-cloudformation&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--template-body&lt;/code&gt;: The path to the template file, which is &lt;code&gt;spring-boot-cloudformation-template-cfn.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--parameters&lt;/code&gt;: The parameters to pass to the template, which is the key pair name &lt;code&gt;aws-key-pair&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--capabilities&lt;/code&gt;: The capabilities to pass to the template, which is &lt;code&gt;CAPABILITY_NAMED_IAM&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Upload the Spring Boot Application &lt;code&gt;.jar&lt;/code&gt; File to the S3 Bucket&lt;/h3&gt;
&lt;p&gt;First, you need to create a &lt;code&gt;.jar&lt;/code&gt; file of the Spring Boot application. To do that, you can use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mvn clean install
mvn clean package
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command creates a &lt;code&gt;.jar&lt;/code&gt; file of the Spring Boot application in the &lt;code&gt;target&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Next, you need to upload the &lt;code&gt;.jar&lt;/code&gt; file to the S3 bucket. To do that, you can use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_S3_BUCKET_NAME=$(aws cloudformation describe-stacks \
  --stack-name spring-boot-cloudformation \
  --query &amp;#39;Stacks[0].Outputs[?OutputKey==`S3CodeBucket`].OutputValue&amp;#39; \
  --output text)

aws s3 cp target/spring-boot-web-0.0.1-SNAPSHOT.jar s3://$AWS_S3_BUCKET_NAME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command uploads the &lt;code&gt;.jar&lt;/code&gt; file to the S3 bucket:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_S3_BUCKET_NAME&lt;/code&gt;: The name of the S3 bucket, which is the output of the &lt;code&gt;S3CodeBucket&lt;/code&gt; output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;target/spring-boot-web-0.0.1-SNAPSHOT.jar&lt;/code&gt;: The path to the &lt;code&gt;.jar&lt;/code&gt; file, which is the &lt;code&gt;.jar&lt;/code&gt; file of the Spring Boot application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Connect to the EC2 Instance&lt;/h3&gt;
&lt;p&gt;To connect to the EC2 instance, you need to get the public IP address of the EC2 instance. To do that, you can use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_EC2_PUBLIC_IP=$(aws cloudformation describe-stacks \
  --stack-name spring-boot-cloudformation \
  --query &amp;#39;Stacks[0].Outputs[?OutputKey==`SpringBootEC2PublicIP`].OutputValue&amp;#39; \
  --output text)

ssh -i ~/.ssh/aws-key-pair.pem ec2-user@$AWS_EC2_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command connects to the EC2 instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_EC2_PUBLIC_IP&lt;/code&gt;: The public IP address of the EC2 instance, which is the output of the &lt;code&gt;SpringBootEC2PublicIP&lt;/code&gt; output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/aws-key-pair.pem&lt;/code&gt;: The path to the key pair file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0037-how-to-deploy-a-spring-boot-application-to-aws-cloudformation/spring-boot-cloudformation-ec2-instance.png&quot; alt=&quot;Spring Boot CloudFormation EC2 Instance&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Run the Spring Boot Application&lt;/h3&gt;
&lt;p&gt;Get the &lt;code&gt;.jar&lt;/code&gt; file from the S3 bucket:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 ls

# copy the bucket name from the output
aws s3 cp s3://&amp;lt;bucket-name&amp;gt;/spring-boot-web-0.0.1-SNAPSHOT.jar .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command gets the &lt;code&gt;.jar&lt;/code&gt; file from the S3 bucket.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0037-how-to-deploy-a-spring-boot-application-to-aws-cloudformation/spring-boot-cloudformation-s3-bucket.png&quot; alt=&quot;Spring Boot CloudFormation S3 Bucket&quot;&gt;&lt;/p&gt;
&lt;p&gt;Run the Spring Boot application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;java -jar spring-boot-web-0.0.1-SNAPSHOT.jar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command runs the Spring Boot application.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0037-how-to-deploy-a-spring-boot-application-to-aws-cloudformation/spring-boot-cloudformation-run-spring-boot-application.png&quot; alt=&quot;Spring Boot CloudFormation Run Spring Boot Application&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Access the Spring Boot Application&lt;/h3&gt;
&lt;p&gt;To access the Spring Boot application, you need to get the public DNS of the EC2 instance. To do that, you can use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_EC2_PUBLIC_DNS=$(aws cloudformation describe-stacks \
  --stack-name spring-boot-cloudformation \
  --query &amp;#39;Stacks[0].Outputs[?OutputKey==`SpringBootEC2PublicDNS`].OutputValue&amp;#39; \
  --output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command gets the public DNS of the EC2 instance.&lt;/p&gt;
&lt;p&gt;Open the public DNS in the browser:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;open http://$AWS_EC2_PUBLIC_DNS:8080/hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command opens the public DNS in the browser.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0037-how-to-deploy-a-spring-boot-application-to-aws-cloudformation/spring-boot-cloudformation-access-spring-boot-application.png&quot; alt=&quot;Spring Boot CloudFormation Access Spring Boot Application&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Run the Spring Boot Application as a Service&lt;/h3&gt;
&lt;p&gt;To run the Spring Boot application as a service, you need to create a service file. To do that, you can use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo vi /etc/systemd/system/spring-boot-web.service
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;[Unit]
Description=Spring Boot Web
After=network.target

[Service]
User=ec2-user
WorkingDirectory=/home/ec2-user
ExecStart=/usr/bin/java -jar spring-boot-web-0.0.1-SNAPSHOT.jar &amp;gt; /home/ec2-user/spring-boot-web.log 2&amp;gt;&amp;amp;1 &amp;amp;
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command creates a service file.&lt;/p&gt;
&lt;p&gt;Reload the daemon:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command reloads the daemon.&lt;/p&gt;
&lt;p&gt;Start the service:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo systemctl start spring-boot-web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command starts the service.&lt;/p&gt;
&lt;p&gt;Enable the service:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo systemctl enable spring-boot-web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command enables the service.&lt;/p&gt;
&lt;p&gt;Check the status of the service:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo systemctl status spring-boot-web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command checks the status of the service.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0037-how-to-deploy-a-spring-boot-application-to-aws-cloudformation/spring-boot-cloudformation-run-spring-boot-application-as-a-service.png&quot; alt=&quot;Spring Boot CloudFormation Run Spring Boot Application as a Service&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Delete the Stack&lt;/h3&gt;
&lt;p&gt;To delete the stack, you can use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws cloudformation delete-stack --stack-name spring-boot-cloudformation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command deletes the stack.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In conclusion, deploying a Spring Boot application to AWS CloudFormation can provide many benefits such as scalability and easy management. By following the steps outlined in this article, you should now have a solid understanding of how to deploy a Spring Boot application to AWS CloudFormation. From creating a CloudFormation template, to packaging the application into a deployable artifact, updating the stack with the new version of the application and setting up continuous deployment, the guide covers all the necessary steps for a successful deployment. Keep in mind that this guide assumes that you have met all the prerequisites and are familiar with the Spring Boot application&amp;#39;s dependencies and configuration. With this knowledge, you should be able to deploy your Spring Boot application to AWS CloudFormation with confidence.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;Here are some references that you can use to learn more about the topics covered in this article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://spring.io/projects/spring-boot&quot;&gt;Spring Boot Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&quot;&gt;AWS CloudFormation User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-reference.html&quot;&gt;AWS CloudFormation Template Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS Command Line Interface (CLI) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html&quot;&gt;Amazon S3 User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/deployment.html&quot;&gt;Deploying Spring Boot Applications - Spring Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/devops/aws-cloudformation-best-practices/&quot;&gt;AWS CloudFormation Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spring.io/guides/gs/spring-boot/&quot;&gt;Creating a Spring Boot Project with Maven&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacks.html&quot;&gt;Working with AWS CloudFormation Stacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/sdk-for-java/&quot;&gt;AWS SDK for Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/deployment.html#deployment.installing.nix-services.systemd&quot;&gt;Running Spring Boot Applications as a Service (systemd)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;AWS Well-Architected Framework&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>Spring Boot</category><category>CloudFormation</category><category>DevOps</category><category>Java</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0037-how-to-deploy-a-spring-boot-application-to-aws-cloudformation/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Introduction to Spring Boot Framework</title><link>https://mkabumattar.com/blog/post/introduction-to-spring-boot-framework/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/introduction-to-spring-boot-framework/</guid><description>For creating web apps and microservices, many developers utilize the Spring Boot framework. The fact that it is built on top of the Spring Framework and offers a number of advantages makes it a desirable option for developers. You will learn about Spring Boot in this blog article, as well as why it is such a great tool for creating web apps and how to create a basic Spring Boot application.</description><pubDate>Sun, 15 Jan 2023 11:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;For creating web apps and microservices, many developers utilize the Spring Boot framework. The fact that it is built on top of the Spring Framework and offers a number of advantages makes it a desirable option for developers. You will learn about Spring Boot in this blog article, as well as why it is such a great tool for creating web apps and how to create a basic Spring Boot application.&lt;/p&gt;
&lt;h2&gt;What is Spring Boot?&lt;/h2&gt;
&lt;p&gt;Developers may quickly and simply construct standalone, production-ready apps using the Spring Boot framework. It offers a variety of capabilities, including security, data access, and online services, that may be quickly added to an application. Furthermore, Spring Boot configures itself automatically depending on the dependencies present in the project, doing away with the need for manual configuration.&lt;/p&gt;
&lt;h2&gt;Why Spring Boot?&lt;/h2&gt;
&lt;p&gt;Due to its simplicity of use and extensive feature set, Spring Boot is a preferred option for developing web apps and microservices. Developers find it appealing because of its extensive variety of capabilities and capacity to customize itself automatically. Its support for testing and deployment also make it a strong and trustworthy framework for creating web applications.&lt;/p&gt;
&lt;h2&gt;Spring Boot Features&lt;/h2&gt;
&lt;h3&gt;Easy Setup and Automatic Configuration&lt;/h3&gt;
&lt;p&gt;One of Spring Boot&amp;#39;s main advantages is its capacity to automatically configure itself in accordance with the dependencies present in the project. As a result, there is no longer a requirement for developers to manually setup the program, which cuts down on the time and effort needed to get an application up and operating.&lt;/p&gt;
&lt;h3&gt;Stand-Alone Applications&lt;/h3&gt;
&lt;p&gt;Easy creation and execution of standalone apps is another significant benefit of Spring Boot. This is made possible via the Spring Boot CLI, which enables programmers to rapidly construct a new application by executing a single command.&lt;/p&gt;
&lt;h3&gt;Web Development&lt;/h3&gt;
&lt;p&gt;Support for RESTful web services, web sockets, and data validation are just a few of the capabilities that Spring Boot offers for creating online applications. Additionally, it interfaces with a variety of well-known web development tools, like Mustache, FreeMarker, and Thymeleaf, making it simple to build dynamic, interactive web pages.&lt;/p&gt;
&lt;h3&gt;Testing and Deployment&lt;/h3&gt;
&lt;p&gt;A variety of features for testing and deploying apps are also offered by Spring Boot. Unit testing tools like JUnit and Mockito are supported by the framework. Additionally, Spring Boot offers a variety of tools, such as metrics and health checks, for administering and monitoring an application once it has been launched.&lt;/p&gt;
&lt;h2&gt;Build a simple Spring Boot Application&lt;/h2&gt;
&lt;h3&gt;Create a Spring Boot Project&lt;/h3&gt;
&lt;p&gt;The first step to building a Spring Boot application is to create a new project. This can be done using the Spring Initializer website (&lt;a href=&quot;https://start.spring.io&quot;&gt;https://start.spring.io&lt;/a&gt;) or the Spring Boot CLI.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl https://start.spring.io/starter.tgz \
  -d baseDir=spring-boot-web \
  -d version=0.0.1-SNAPSHOT \
  -d type=maven-project \
  -d language=java \
  -d bootVersion=2.4.2 \
  -d groupId=io.github.mkabumattar \
  -d artifactId=spring-boot-web \
  -d name=spring-boot-web \
  -d packageName=io.github.mkabumattar.springbootweb \
  -d dependencies=web \
  -d packaging=jar \
  -d javaVersion=11 \
  -d dependencies=web \
  | tar -xzvf -
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command uses &lt;code&gt;curl&lt;/code&gt; to download a &lt;code&gt;starter.tgz&lt;/code&gt; file from the Spring Initializer website, with the specified options passed in as query parameters. The options include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;baseDir&lt;/code&gt;, which sets the base directory for the project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;version&lt;/code&gt;, which sets the version of the project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt;, which specifies that the project is a Maven project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;language&lt;/code&gt;, which sets the programming language of the project as Java&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bootVersion&lt;/code&gt;, which sets the version of Spring Boot to use in the project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;groupId&lt;/code&gt;, which sets the Maven groupId for the project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;artifactId&lt;/code&gt;, which sets the Maven artifactId for the project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;, which sets the name of the project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;packageName&lt;/code&gt;, which sets the package name for the project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dependencies&lt;/code&gt;, which sets the dependencies needed for the project. In this case, it is web&lt;/li&gt;
&lt;li&gt;&lt;code&gt;packaging&lt;/code&gt;, which sets the packaging format as a JAR file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;javaVersion&lt;/code&gt;, which sets the Java version to be used in the project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dependencies&lt;/code&gt;, which sets the dependencies needed for the project. In this case, it is web&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The output of this command is then piped to &lt;code&gt;tar&lt;/code&gt; command which is used to extract the downloaded file. The options passed to &lt;code&gt;tar&lt;/code&gt; command are &lt;code&gt;xzvf -&lt;/code&gt; which means extract the archive, gzip compressed, verbosely, to stdout.&lt;/p&gt;
&lt;p&gt;This command will download and extract a new Spring Boot project with the specified options. The project will have a directory structure that is typical of a Maven project, and it will have the Spring Web dependency already set up and configured.&lt;/p&gt;
&lt;h3&gt;Create a Controller&lt;/h3&gt;
&lt;p&gt;The creation of a controller is the next step in handling requests for the application. A Java class called a &amp;quot;controller&amp;quot; is in charge of managing incoming HTTP requests and providing the proper answer. Here is an illustration of a straightforward controller that sends back the JSON object &amp;quot;Hello World&amp;quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;package io.github.mkabumattar.springbootweb.controllers;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class HelloWorldController {

    @GetMapping(&amp;quot;/hello&amp;quot;)
    public Map&amp;lt;String, String&amp;gt; sayHello() {
        Map&amp;lt;String, String&amp;gt; response = new HashMap&amp;lt;&amp;gt;();
        response.put(&amp;quot;message&amp;quot;, &amp;quot;Hello World!&amp;quot;);
        return response;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;@GetMapping&lt;/code&gt; annotation instructs Spring that this method should handle GET requests to the &lt;code&gt;/hello&lt;/code&gt; endpoint, and the &lt;code&gt;@RestController&lt;/code&gt; annotation instructs Spring that this class should be handled as a REST controller in this example. The function provides a straightforward map with a single key-value pair, with the value &amp;quot;Hello World&amp;quot; and the key &amp;quot;message.&amp;quot;&lt;/p&gt;
&lt;p&gt;This is a straightforward example of a Spring Boot controller, but it may be enhanced to handle more complicated routes, accept various requests, and deliver more sophisticated results.&lt;/p&gt;
&lt;h3&gt;Run the Application&lt;/h3&gt;
&lt;p&gt;The main method in the produced &lt;code&gt;SpringBootWebApplication.java&lt;/code&gt; file or the &lt;code&gt;spring-boot:run&lt;/code&gt; command (if using the Spring Boot CLI) may be used to launch the application after it has been constructed and a controller has been added.&lt;/p&gt;
&lt;p&gt;The program may also be launched by developing it and launching the produced jar file. Use the &lt;code&gt;mvn clean install&lt;/code&gt; command to create a Spring Boot application using Maven, and then use &lt;code&gt;java -jar target/your-jar-file.jar&lt;/code&gt; to launch the created jar file.&lt;/p&gt;
&lt;p&gt;When the application is up and running, it will by default be reachable at &lt;code&gt;http://localhost:8080&lt;/code&gt;. By accessing the endpoint &lt;code&gt;http://localhost:8080/hello&lt;/code&gt; in the browser or by sending a GET request to that endpoint using a program like curl or postman, you may test the application. The answer must be a json object with a key-value pair with the value &amp;quot;Hello World&amp;quot; and the key &amp;quot;message.&amp;quot;&lt;/p&gt;
&lt;p&gt;By utilizing the &lt;code&gt;server.port&lt;/code&gt; parameter in the &lt;code&gt;application.properties&lt;/code&gt; file or by adding &lt;code&gt; -server.port=your-port-number&amp;gt;&lt;/code&gt; to the command line arguments when executing the application, you may also select a different port number to use when running the program.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s crucial to remember that Spring Boot will automatically establish an embedded Tomcat, Jetty, or Undertow server when you begin the application in order to process web requests and execute your application on it.&lt;/p&gt;
&lt;h3&gt;Test the Application&lt;/h3&gt;
&lt;p&gt;After launching the Spring Boot application, you may test it to make sure everything is operating as it should. Making a request to the endpoint(s) specified in the controller(s) using a web browser or a tool like &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;postman&lt;/code&gt; and observing the outcome is one method of testing the application.&lt;/p&gt;
&lt;p&gt;You may test it, for instance, by visiting the URL &lt;code&gt;http://localhost:8080/hello&lt;/code&gt; in a web browser or by sending a GET request to that endpoint using a tool like &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;postman&lt;/code&gt;. For example, in the preceding example, we created a &lt;code&gt;HelloWorldController&lt;/code&gt; that handles the &lt;code&gt;/hello&lt;/code&gt; endpoint. A json object having a key-value pair, with the value &amp;quot;Hello World&amp;quot; and the key &amp;quot;message,&amp;quot; should be the response.&lt;/p&gt;
&lt;p&gt;Making use of a testing framework like JUnit or TestNG, unit tests might be another approach to test the application. The controllers, services, and repository classes are just a few examples of the components of the application that may be tested using these tests. To make it simple to develop tests for a Spring Boot application, Spring Boot offers a variety of annotations and services.&lt;/p&gt;
&lt;p&gt;JUnit, a well-liked testing framework for Java applications, can be used as one method of testing a Spring Boot application. Unit tests for specific application parts, such the controllers, services, and repository classes, may be developed using JUnit.&lt;/p&gt;
&lt;p&gt;You must include the JUnit dependency in the &lt;code&gt;pom.xml&lt;/code&gt; file of a Spring Boot application that uses Maven as a build tool in order to use JUnit.&lt;/p&gt;
&lt;p&gt;Here is an example of how you can add JUnit to your &lt;code&gt;pom.xml&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;4.13.2&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JUnit, a well-liked testing framework for Java applications, can be used as one method of testing a Spring Boot application. Unit tests for specific application parts, such the controllers, services, and repository classes, may be developed using JUnit.&lt;/p&gt;
&lt;p&gt;Here is an example of how you can use JUnit to test a simple REST controller:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;package io.github.mkabumattar.springbootweb.controllers;

import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloWorldControllerTest {
    private MockMvc mockMvc;

    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build();
    }

    @Test
    public void testSayHello() throws Exception {
        mockMvc.perform(get(&amp;quot;/hello&amp;quot;))
                .andExpect(status().isOk())
                .andExpect(jsonPath(&amp;quot;$.message&amp;quot;, is(&amp;quot;Hello World!&amp;quot;)));
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In conclusion, Spring Boot is an effective framework for creating Java web apps. Automatic setup, stand-alone applications, web development, testing, and deployment are just a few of the capabilities it offers to make it simple to set up, configure, and execute a Spring-based application.&lt;/p&gt;
&lt;p&gt;We have covered the fundamentals of Spring Boot in this post, along with how to construct a straightforward Spring Boot application. The steps for creating a project, including how to add a Spring Web dependency, a controller, run the application, and test it, have all been demonstrated. Additionally, we spoke about how to test the application using MockMvc and JUnit.&lt;/p&gt;
&lt;p&gt;For creating web apps, Spring Boot is a fantastic option since it is simple to get started with and offers a ton of functionality right out of the box. You can discover a lot of tools to help you create and launch your application thanks to its extensive documentation and vast community.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s crucial to remember that when it comes to Spring Boot&amp;#39;s possibilities, this is simply the top of the iceberg. You will get more familiar with the framework&amp;#39;s capabilities as you use it more, and you&amp;#39;ll learn how to leverage them to create applications that are more intricate and potent.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;Here are some references that you can use to learn more about Spring Boot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://spring.io/projects/spring-boot&quot;&gt;Spring Boot Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/&quot;&gt;Spring Boot Reference Guide (Current Version)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://start.spring.io/&quot;&gt;Spring Initializr&lt;/a&gt; - Tool for bootstrapping Spring Boot projects.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spring.io/docs&quot;&gt;Spring Framework Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spring.io/guides/gs/rest-service/&quot;&gt;Building a RESTful Web Service with Spring Boot&lt;/a&gt; - Official Spring Guide.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/spring-projects/spring-boot&quot;&gt;Spring Boot GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/spring-boot&quot;&gt;Baeldung - Spring Boot Tutorials&lt;/a&gt; (Popular community resource)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://maven.apache.org/&quot;&gt;Maven Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://junit.org/junit5/docs/current/user-guide/&quot;&gt;JUnit 5 User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing&quot;&gt;Spring Boot Testing&lt;/a&gt; - Official documentation on testing.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spring.io/guides/gs/spring-boot/#what-is-spring-boot&quot;&gt;What is Spring Boot? - spring.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/cli.html&quot;&gt;Spring Boot CLI Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.thymeleaf.org/documentation.html&quot;&gt;Thymeleaf Documentation (for web development with Spring Boot)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#spring-mvc-test-server&quot;&gt;MockMvc - Spring Framework Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Java</category><category>Spring Framework</category><category>Backend Development</category><category>Microservices</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0036-introduction-to-spring-boot-framework/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Setup Bastion Host on AWS using CloudFormation Template</title><link>https://mkabumattar.com/blog/post/how-to-setup-bastion-host-on-aws-using-cloudformation-template/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-setup-bastion-host-on-aws-using-cloudformation-template/</guid><description>Learn how to set up a secure Bastion Host on AWS using CloudFormation templates. This tutorial covers all the steps needed to create a VPC, subnets, security groups, and instances, and test the Internet connectivity. Detailed instructions and sample code are included.</description><pubDate>Tue, 10 Jan 2023 22:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In previous post &lt;a href=&quot;/blog/post/how-to-setup-bastion-host-on-aws-using-aws-cli&quot;&gt;How To Setup Bastion Host on AWS using CloudFormation Template&lt;/a&gt;, we will learn how to setup a Bastion host on AWS using a CloudFormation template. We will walk through the process of creating a CloudFormation template, deploying it, and connecting to the instances created by the template. This is a simple and efficient way of setting up a Bastion host on AWS.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before starting, make sure that you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI installed and configured on your local machine. You can follow the instructions on &lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html&quot;&gt;Installing the AWS CLI&lt;/a&gt; to install and configure it.&lt;/li&gt;
&lt;li&gt;An IAM user with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonVPCFullAccess&lt;/li&gt;
&lt;li&gt;AmazonEC2FullAccess&lt;/li&gt;
&lt;li&gt;AWSCloudFormationFullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Basic knowledge of networking and SSH&lt;/li&gt;
&lt;li&gt;Familiarity with YAML and AWS CloudFormation&lt;/li&gt;
&lt;li&gt;AWS CLI version 2 or later.&lt;/li&gt;
&lt;li&gt;The AWS CLI configured with the desired credentials&lt;/li&gt;
&lt;li&gt;Knowledge of AWS basic building blocks such as VPCs, Subnets, Security Groups, Elastic IPs and EC2 instances.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To create an IAM user, follow the instructions on &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html&quot;&gt;Creating an IAM User&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Setup Bastion Host on AWS using CloudFormation Template&lt;/h2&gt;
&lt;h3&gt;Create a CloudFormation Template&lt;/h3&gt;
&lt;p&gt;Create a new file called &lt;code&gt;bastion-host-with-vpc.yml&lt;/code&gt; and include the CloudFormation template code. This should include the necessary resources such as VPC, subnets, security groups, Elastic IPs, Internet Gateway, NAT Gateway, and EC2 instances. Make sure to specify the correct parameters such as subnet IDs, security group IDs, and key pair names.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml:bastion-host-with-vpc.yml&quot;&gt;AWSTemplateFormatVersion: &amp;#39;2010-09-09&amp;#39;
Description: &amp;gt;-
  This template creates a VPC with 2 subnets, 1 public and 1 private. It also
  Internet Gateway, NAT Gateway, Route Tables, Security Groups and EC2 Instances
  for Bastion Host and Private Instance.

Parameters:
  EnvironmentName:
    Description: &amp;gt;-
      An environment name that will be prefixed to resource names
    Type: String
    AllowedValues:
      - dev
      - test
      - prod
    Default: dev
  VPCName:
    Description: &amp;gt;-
      The name of the VPC. This name is used as a tag value for the VPC and
      subnets.
    Type: String
    Default: bastion-host-vpc
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      VPC name can include numbers, lowercase letters, uppercase letters, and
      hyphens (-). It cannot start or end with a hyphen (-).
  VPCCIDR:
    Description: &amp;gt;-
      The CIDR block for the VPC. This should be a valid private (RFC 1918)
      CIDR range.
    Type: String
    Default: 10.0.0.0/16
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-9]|3[0-2]))$
    ConstraintDescription: &amp;gt;-
      CIDR block parameter must be in the form x.x.x.x/16-32, where x is a
      number from 0-255, and /16-32 is a valid CIDR range.
  PublicSubnetName:
    Description: &amp;gt;-
      The name of the public subnet. This name is used as a tag value for the
      subnet.
    Type: String
    Default: bastion-host-public-subnet
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Subnet name can include numbers, lowercase letters, uppercase letters, and
      hyphens (-). It cannot start or end with a hyphen (-).
  PublicSubnetCIDR:
    Description: &amp;gt;-
      The CIDR block for the public subnet. This should be a valid private (RFC
      1918) CIDR range that is /24 or larger.
    Type: String
    Default: 10.0.0.0/24
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(2[4-9]|3[0-2]))$
    ConstraintDescription: &amp;gt;-
      CIDR block parameter must be in the form x.x.x.x/24-32, where x is a
      number from 0-255, and /24-32 is a valid CIDR range.
  PrivateSubnetName:
    Description: &amp;gt;-
      The name of the private subnet. This name is used as a tag value for the
      subnet.
    Type: String
    Default: bastion-host-private-subnet
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Subnet name can include numbers, lowercase letters, uppercase letters, and
      hyphens (-). It cannot start or end with a hyphen (-).
  PrivateSubnetCIDR:
    Description: &amp;gt;-
      The CIDR block for the private subnet. This should be a valid private (RFC
      1918) CIDR range that is /24 or larger.
    Type: String
    Default: 10.0.16.0/24
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(2[4-9]|3[0-2]))$
    ConstraintDescription: &amp;gt;-
      CIDR block parameter must be in the form x.x.x.x/24-32, where x is a
      number from 0-255, and /24-32 is a valid CIDR range.
  InternetGatewayName:
    Description: &amp;gt;-
      The name of the Internet Gateway. This name is used as a tag value for the
      Internet Gateway.
    Type: String
    Default: bastion-host-igw
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Internet Gateway name can include numbers, lowercase letters, uppercase
      letters, and hyphens (-). It cannot start or end with a hyphen (-).
  NATGatewayName:
    Description: &amp;gt;-
      The name of the NAT Gateway. This name is used as a tag value for the NAT
      Gateway.
    Type: String
    Default: bastion-host-ngw
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      NAT Gateway name can include numbers, lowercase letters, uppercase
      letters, and hyphens (-). It cannot start or end with a hyphen (-).
  PublicRouteTableName:
    Description: &amp;gt;-
      The name of the public route table. This name is used as a tag value for
      the route table.
    Type: String
    Default: bastion-host-public-route-table
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Route table name can include numbers, lowercase letters, uppercase
      letters, and hyphens (-). It cannot start or end with a hyphen (-).
  PrivateRouteTableName:
    Description: &amp;gt;-
      The name of the private route table. This name is used as a tag value for
      the route table.
    Type: String
    Default: bastion-host-private-route-table
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Route table name can include numbers, lowercase letters, uppercase
      letters, and hyphens (-). It cannot start or end with a hyphen (-).
  BastionHostName:
    Description: &amp;gt;-
      The name of the Bastion Host instance. This name is used as a tag value
      for the instance.
    Type: String
    Default: bastion-host-instance
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
  BastionHostKeyPair:
    Description: &amp;gt;-
      The name of an existing EC2 KeyPair to enable SSH access to the Bastion
      Host.
    Type: AWS::EC2::KeyPair::KeyName
  BastionHostType:
    Description: &amp;gt;-
      The instance type to use for the Bastion Host.
    Type: String
    AllowedValues:
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - t3.nano
      - t3.micro
      - t3.small
      - t3.medium
      - t3.large
      - t3.xlarge
      - t3.2xlarge
      - m1.small
      - m1.medium
      - m1.large
      - m1.xlarge
      - m2.xlarge
      - m2.2xlarge
      - m2.4xlarge
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - m4.16xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
      - m5.12xlarge
      - m5.24xlarge
      - m5d.large
      - m5d.xlarge
      - m5d.2xlarge
      - m5d.4xlarge
      - m5d.12xlarge
      - m5d.24xlarge
      - c1.medium
      - c1.xlarge
      - c3.large
      - c3.xlarge
      - c3.2xlarge
      - c3.4xlarge
      - c3.8xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5.9xlarge
    Default: t2.micro
    ConstraintDescription: &amp;gt;-
      Must be a valid EC2 instance type.
  BastionHostAMI:
    Description: &amp;gt;-
      The ID of the Amazon Machine Image (AMI) that you want to use to launch
      the Bastion Host instance.
    Type: AWS::SSM::Parameter::Value&amp;lt;AWS::EC2::Image::Id&amp;gt;
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
  BastionHostSecurityGroupName:
    Description: &amp;gt;-
      The name of the security group to assign to the Bastion Host instance.
    Type: String
    Default: bastion-host-security-group
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Security group name can include numbers, lowercase letters, uppercase
      letters, and hyphens (-). It cannot start or end with a hyphen (-).
  BastionHostSecurityGroupDescription:
    Description: &amp;gt;-
      The description of the security group to assign to the Bastion Host
      instance.
    Type: String
    Default: Bastion Host security group
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9\s]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Security group description can include numbers, lowercase letters,
      uppercase letters, and hyphens (-). It cannot start or end with a hyphen
      (-).
  PrivateInstanceName:
    Description: &amp;gt;-
      The name of the private instance. This name is used as a tag value for the
      instance.
    Type: String
    Default: bastion-host-private-instance
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Instance name can include numbers, lowercase letters, uppercase letters,
      and hyphens (-). It cannot start or end with a hyphen (-).
  PrivateInstanceKeyPair:
    Description: &amp;gt;-
      The name of the Amazon EC2 key pair that you want to use to connect to the
      private instance.
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: &amp;gt;-
      Must be the name of an existing Amazon EC2 key pair.
  PrivateInstanceType:
    Description: &amp;gt;-
      The instance type to use for the private instance.
    Type: String
    AllowedValues:
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - t3.nano
      - t3.micro
      - t3.small
      - t3.medium
      - t3.large
      - t3.xlarge
      - t3.2xlarge
      - m1.small
      - m1.medium
      - m1.large
      - m1.xlarge
      - m2.xlarge
      - m2.2xlarge
      - m2.4xlarge
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - m4.16xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
      - m5.12xlarge
      - m5.24xlarge
      - m5d.large
      - m5d.xlarge
      - m5d.2xlarge
      - m5d.4xlarge
      - m5d.12xlarge
      - m5d.24xlarge
      - c1.medium
      - c1.xlarge
      - c3.large
      - c3.xlarge
      - c3.2xlarge
      - c3.4xlarge
      - c3.8xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5.9xlarge
    Default: t2.micro
    ConstraintDescription: &amp;gt;-
      Must be a valid EC2 instance type.
  PrivateInstanceAMI:
    Description: &amp;gt;-
      The ID of the Amazon Machine Image (AMI) that you want to use to launch
      the private instance.
    Type: AWS::SSM::Parameter::Value&amp;lt;AWS::EC2::Image::Id&amp;gt;
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
  PrivateInstanceSecurityGroupName:
    Description: &amp;gt;-
      The name of the security group to assign to the private instance.
    Type: String
    Default: bastion-host-private-instance-security-group
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Security group name can include numbers, lowercase letters, uppercase
      letters, and hyphens (-). It cannot start or end with a hyphen (-).
  PrivateInstanceSecurityGroupDescription:
    Description: &amp;gt;-
      The description of the security group to assign to the private instance.
    Type: String
    Default: Bastion Host private instance security group
    AllowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9\s]*[a-zA-Z0-9]$
    ConstraintDescription: &amp;gt;-
      Security group description can include numbers, lowercase letters,
      uppercase letters, and hyphens (-). It cannot start or end with a hyphen
      (-).

Metadata:
  Author: Mohammad Abu Mattar
  Version: 1.0
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Environment
        Parameters:
          - EnvironmentName
      - Label:
          default: Natwork Configuration
        Parameters:
          - VPCName
          - VPCCIDR
          - PublicSubnetName
          - PublicSubnetCIDR
          - PrivateSubnetName
          - PrivateSubnetCIDR
          - InternetGatewayName
          - NATGatewayName
          - PublicRouteTableName
          - PrivateRouteTableName
      - Label:
          default: Bastion Host Configuration
        Parameters:
          - BastionHostName
          - BastionHostKeyPair
          - BastionHostType
          - BastionHostAMI
          - BastionHostSecurityGroupName
          - BastionHostSecurityGroupDescription
      - Label:
          default: Private Instance Configuration
        Parameters:
          - PrivateInstanceName
          - PrivateInstanceKeyPair
          - PrivateInstanceType
          - PrivateInstanceAMI
          - PrivateInstanceSecurityGroupName
          - PrivateInstanceSecurityGroupDescription

    ParameterLabels:
      EnvironmentName:
        default: Environment Name
      VPCName:
        default: VPC Name
      VPCCIDR:
        default: VPC CIDR
      PublicSubnetName:
        default: Public Subnet Name
      PublicSubnetCIDR:
        default: Public Subnet CIDR
      PrivateSubnetName:
        default: Private Subnet Name
      PrivateSubnetCIDR:
        default: Private Subnet CIDR
      InternetGatewayName:
        default: Internet Gateway Name
      NATGatewayName:
        default: NAT Gateway Name
      PublicRouteTableName:
        default: Public Route Table Name
      PrivateRouteTableName:
        default: Private Route Table Name
      BastionHostName:
        default: Bastion Host Name
      BastionHostKeyPair:
        default: Bastion Host Key Pair
      BastionHostType:
        default: Bastion Host Type
      BastionHostAMI:
        default: Bastion Host AMI
      BastionHostSecurityGroupName:
        default: Bastion Host Security Group Name
      BastionHostSecurityGroupDescription:
        default: Bastion Host Security Group Description
      PrivateInstanceName:
        default: Private Instance Name
      PrivateInstanceKeyPair:
        default: Private Instance Key Pair
      PrivateInstanceType:
        default: Private Instance Type
      PrivateInstanceAMI:
        default: Private Instance AMI
      PrivateInstanceSecurityGroupName:
        default: Private Instance Security Group Name
      PrivateInstanceSecurityGroupDescription:
        default: Private Instance Security Group Description

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Ref VPCName

  PublicSubnet:
    Type: AWS::EC2::Subnet
    DependsOn:
      - VPC
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PublicSubnetCIDR
      AvailabilityZone: !Select [0, !GetAZs &amp;#39;&amp;#39;]
      Tags:
        - Key: Name
          Value: !Ref PublicSubnetName
  PriveSubnet:
    Type: AWS::EC2::Subnet
    DependsOn:
      - VPC
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PrivateSubnetCIDR
      AvailabilityZone: !Select [0, !GetAZs &amp;#39;&amp;#39;]
      Tags:
        - Key: Name
          Value: !Ref PrivateSubnetName

  IGW:
    Type: AWS::EC2::InternetGateway
    DependsOn:
      - VPC
    Properties:
      Tags:
        - Key: Name
          Value: !Ref InternetGatewayName
  IGWAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    DependsOn:
      - VPC
      - IGW
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref IGW

  NATGatewayEIP:
    Type: AWS::EC2::EIP
    DependsOn:
      - VPC
    Properties:
      Domain: vpc
  NATGateway:
    Type: AWS::EC2::NatGateway
    DependsOn:
      - VPC
      - PublicSubnet
      - NATGatewayEIP
    Properties:
      AllocationId: !GetAtt NATGatewayEIP.AllocationId
      SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: !Ref NATGatewayName

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn:
      - VPC
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Ref PublicRouteTableName
  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn:
      - VPC
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Ref PrivateRouteTableName

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn:
      - PublicRouteTable
      - IGW
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref IGW
  PrivateRoute:
    Type: AWS::EC2::Route
    DependsOn:
      - PrivateRouteTable
      - NATGateway
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    DependsOn:
      - PublicSubnet
      - PublicRouteTable
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable
  PrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    DependsOn:
      - PriveSubnet
      - PrivateRouteTable
    Properties:
      SubnetId: !Ref PriveSubnet
      RouteTableId: !Ref PrivateRouteTable

  BastionHostSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    DependsOn:
      - VPC
    Properties:
      GroupDescription: !Ref BastionHostSecurityGroupDescription
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Ref BastionHostSecurityGroupName
  PrivateInstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    DependsOn:
      - VPC
    Properties:
      GroupDescription: !Ref PrivateInstanceSecurityGroupDescription
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          SourceSecurityGroupId: !Ref BastionHostSecurityGroup
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Ref PrivateInstanceSecurityGroupName

  BastionHost:
    Type: AWS::EC2::Instance
    DependsOn:
      - PublicSubnet
      - BastionHostSecurityGroup
    Properties:
      ImageId: !Ref BastionHostAMI
      InstanceType: !Ref BastionHostType
      KeyName: !Ref BastionHostKeyPair
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet:
            - !Ref BastionHostSecurityGroup
          SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: !Ref BastionHostName
  PrivateInstance:
    Type: AWS::EC2::Instance
    DependsOn:
      - PriveSubnet
      - PrivateInstanceSecurityGroup
    Properties:
      ImageId: !Ref PrivateInstanceAMI
      InstanceType: !Ref PrivateInstanceType
      KeyName: !Ref PrivateInstanceKeyPair
      NetworkInterfaces:
        - AssociatePublicIpAddress: false
          DeviceIndex: 0
          GroupSet:
            - !Ref PrivateInstanceSecurityGroup
          SubnetId: !Ref PriveSubnet
      Tags:
        - Key: Name
          Value: !Ref PrivateInstanceName

Outputs:
  BastionHostSSH:
    Description: SSH command to connect to the bastion host
    Value: !Join
      - &amp;#39;&amp;#39;
      - - ssh -i ~/.ssh/
        - !Ref BastionHostKeyPair
        - .pem ec2-user@
        - !GetAtt BastionHost.PublicIp
  PrivateInstanceSSH:
    Description: SSH command to connect to the private instance
    Value: !Join
      - &amp;#39;&amp;#39;
      - - ssh -i ~/.ssh/
        - !Ref PrivateInstanceKeyPair
        - .pem ec2-user@
        - !GetAtt PrivateInstance.PrivateIp
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Deploying the stack&lt;/h3&gt;
&lt;p&gt;Use the AWS CLI or the AWS CloudFormation console to create a new stack using the &lt;code&gt;bastion-host-with-vpc.yml&lt;/code&gt; template file. Provide the necessary parameters such as stack name and region. Make sure that the IAM user has the correct permissions to create the resources specified in the template.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0035-how-to-setup-bastion-host-on-aws-using-cloudformation-template/aws-cloudformation-console.png&quot; alt=&quot;AWS CloudFormation console&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Testing the stack&lt;/h3&gt;
&lt;p&gt;Once the stack is deployed, use the SSH commands provided in the outputs to connect to the bastion host and the private instance. Verify that the instances are running, and that the Internet connectivity is working by running the appropriate commands on the instances.&lt;/p&gt;
&lt;h4&gt;Step 1: Connect to the bastion host&lt;/h4&gt;
&lt;p&gt;We can use the SSH command provided in the outputs to connect to the bastion host.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -i ~/.ssh/BastionHostKeyPair.pem ec2-user@&amp;lt;BastionHostPublicIp&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0035-how-to-setup-bastion-host-on-aws-using-cloudformation-template/connect-to-the-bastion-host.png&quot; alt=&quot;Bastion host&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Step 2: Connect to the private instance&lt;/h4&gt;
&lt;p&gt;We can use the SSH command provided in the outputs to connect to the private instance.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -i ~/.ssh/PrivateInstanceKeyPair.pem ec2-user@&amp;lt;PrivateInstancePrivateIp&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 3: Test the connection&lt;/h4&gt;
&lt;p&gt;Now that you are connected to the private host, you can check if the host has internet connectivity by pinging a public IP or URL:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ping -c 4 google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will send 4 ICMP echo requests to the IP address of Google&amp;#39;s website, and the private host will respond with 4 ICMP echo replies if it can reach the internet. This verifies that the NAT gateway and route tables are configured correctly.&lt;/p&gt;
&lt;p&gt;Alternatively, you can also check internet connectivity by using curl command to download a webpage:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0035-how-to-setup-bastion-host-on-aws-using-cloudformation-template/internet-connectivity.png&quot; alt=&quot;Internet Connectivity&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl -s https://www.mkabumattar.tech
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will download the website&amp;#39;s source code and will return it to the terminal, and check if the response is received from the website. If the private host has internet connectivity, it will show the webpage&amp;#39;s source code.&lt;/p&gt;
&lt;p&gt;It is important to note that, if you are running these commands from the bastion host, you might not face the same restrictions as the private host, in that case you should run the commands from the private host, or you could use a specific website for the test that is blocked for your private network&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0035-how-to-setup-bastion-host-on-aws-using-cloudformation-template/internet-connectivity-2.png&quot; alt=&quot;Internet Connectivity&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Cleanup&lt;/h3&gt;
&lt;p&gt;When you are done testing and using the stack, it is a good practice to clean up and delete the stack using the AWS CLI, AWS Console, or the AWS CloudFormation console to avoid unnecessary charges.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we&amp;#39;ve learned how to set up a Bastion Host on AWS using CloudFormation Templates. We&amp;#39;ve gone through the process of creating a CloudFormation Template, deploying the stack, testing the connection, and deleting the stack. By using CloudFormation Templates, we can easily provision and manage our infrastructure in an automated and repeatable way. It&amp;#39;s an efficient method to set up and scale infrastructure. However, it&amp;#39;s important to make sure to clean up the resources when no longer in use to avoid incurring unnecessary costs.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&quot;&gt;AWS CloudFormation User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-reference.html&quot;&gt;AWS CloudFormation Template Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS Command Line Interface (CLI) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&quot;&gt;Amazon Virtual Private Cloud (VPC) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html&quot;&gt;Security Groups for your VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html&quot;&gt;NAT Gateways - Amazon VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html&quot;&gt;Internet Gateways - Amazon VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html&quot;&gt;AWS Key Pairs and Amazon EC2 Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/quickstart/architecture/linux-bastion/&quot;&gt;Linux Bastion Hosts on AWS (Quick Start Reference Deployment)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html&quot;&gt;Controlling Network Traffic with Security Groups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/devops/aws-cloudformation-best-practices/&quot;&gt;AWS CloudFormation Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html&quot;&gt;What is an Elastic IP address?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html&quot;&gt;Connect to your Linux instance using SSH&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>CloudFormation</category><category>Security</category><category>Networking</category><category>DevOps</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0035-how-to-setup-bastion-host-on-aws-using-cloudformation-template/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Setup Bastion Host on AWS using AWS CLI</title><link>https://mkabumattar.com/blog/post/how-to-setup-bastion-host-on-aws-using-aws-cli/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-setup-bastion-host-on-aws-using-aws-cli/</guid><description>In this post, we will learn the best practices of setting up a Bastion Host on AWS using the AWS CLI for secure and remote access to EC2 instances within a Virtual Private Cloud (VPC). We will guide you through creating a VPC, subnets, internet gateway, and configuring the Bastion Host with the appropriate permissions. This post is intended for those who are familiar with AWS and have some basic knowledge of networking and SSH.</description><pubDate>Mon, 09 Jan 2023 22:09:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In today&amp;#39;s world, security is the top priority for any infrastructure and applications, that&amp;#39;s why a Bastion host is a must-have in your infrastructure if you want to secure your remote connections. A Bastion host is a special-purpose computer on a network specifically designed and configured to withstand attacks. In this post, we will show you how to set up a Bastion host on AWS using the AWS CLI. We will create a Virtual Private Cloud (VPC) and subnets, create an Internet Gateway and configure the Bastion host with the appropriate permissions to access our EC2 instances. By the end of this post, you will have a secure and easy way to remotely access your EC2 instances.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before starting, make sure that you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI installed and configured on your local machine. You can follow the instructions on &lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html&quot;&gt;Installing the AWS CLI&lt;/a&gt; to install and configure it.&lt;/li&gt;
&lt;li&gt;An IAM user with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonVPCFullAccess&lt;/li&gt;
&lt;li&gt;AmazonEC2FullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Basic knowledge of networking and SSH&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To create an IAM user, follow the instructions on &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html&quot;&gt;Creating an IAM User&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You will also need to have the AWS CLI configured with your access keys for the IAM user you created above. This can be done by running &lt;code&gt;aws configure&lt;/code&gt; in the command line and providing your access key and secret key.&lt;/p&gt;
&lt;h2&gt;Create VPC&lt;/h2&gt;
&lt;p&gt;In this section, we will create a Virtual Private Cloud (VPC) and its resources such as subnets, internet gateways, etc. This VPC will be the foundation for our Bastion Host, providing a secure and isolated network environment.&lt;/p&gt;
&lt;h3&gt;Step 1: Create VPC&lt;/h3&gt;
&lt;p&gt;First, we need to create a VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_VPC=$(aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --query &amp;#39;Vpc.VpcId&amp;#39; \
  --output text)

aws ec2 create-tags \
  --resources $AWS_VPC \
  --tags Key=Name,Value=vpc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create a VPC with the CIDR block of &lt;code&gt;10.0.0.0/16&lt;/code&gt; and create a name tag for it. The VpcId of the created VPC will be stored in the variable &lt;code&gt;$AWS_VPC&lt;/code&gt; for future reference.&lt;/p&gt;
&lt;h3&gt;Step 2: Modify your VPC and enable DNS hostname and DNS support&lt;/h3&gt;
&lt;p&gt;In this step, we will enable both the DNS hostname and DNS support on our VPC. Enabling these features will allow our instances to resolve DNS hostnames and domain names. By default, these features are disabled when you create a VPC.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-hostnames &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;

aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-support &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above commands will enable the DNS hostname and DNS support for our VPC. &lt;code&gt;--vpc-id&lt;/code&gt; &lt;code&gt;$AWS_VPC&lt;/code&gt; this flag tells the command on which vpc you want to enable these features, where the &lt;code&gt;$AWS_VPC&lt;/code&gt; is a variable that we set in the previous step when we created the VPC.&lt;/p&gt;
&lt;h3&gt;Step 3: Create a Public and a Private subnet&lt;/h3&gt;
&lt;p&gt;In this step, we will create two subnets: one public and one private. A public subnet is a subnet that&amp;#39;s connected to the internet through an internet gateway, whereas a private subnet is a subnet that&amp;#39;s isolated from the internet and can only access the internet through a NAT gateway or VPN connection. In this case, we will connect our Bastion Host to the public subnet and the EC2 instances that we want to access remotely to the private subnet.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_PUBLIC_SUBNET=$(aws ec2 create-subnet \
  --vpc-id $AWS_VPC \
  --cidr-block 10.0.0.0/24 \
  --query &amp;#39;Subnet.SubnetId&amp;#39; \
  --output text)

AWS_PRIVATE_SUBNET=$(aws ec2 create-subnet \
  --vpc-id $AWS_VPC \
  --cidr-block 10.0.16.0/24 \
  --query &amp;#39;Subnet.SubnetId&amp;#39; \
  --output text)

aws ec2 create-tags \
  --resources $AWS_PUBLIC_SUBNET \
  --tags Key=Name,Value=public-subnet

aws ec2 create-tags \
  --resources $AWS_PRIVATE_SUBNET \
  --tags Key=Name,Value=private-subnet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create two subnets, one with a CIDR block of &lt;code&gt;10.0.0.0/24&lt;/code&gt; (public) and one with a CIDR block of &lt;code&gt;10.0.16.0/24&lt;/code&gt; (private) and will associate them with the &lt;code&gt;$AWS_VPC&lt;/code&gt; VPC we created earlier. Also, it will add names to the subnet for the better organization and management, The subnet IDs are stored in the variables &lt;code&gt;$AWS_PUBLIC_SUBNET&lt;/code&gt; and &lt;code&gt;$AWS_PRIVATE_SUBNET&lt;/code&gt; for future reference.&lt;/p&gt;
&lt;h3&gt;Step 4: Enable Auto-assign Public IP on the Public Subnet&lt;/h3&gt;
&lt;p&gt;In this step, we will enable Auto-assign Public IP on the public subnet, which will allow instances launched in this subnet to automatically receive a public IP address. This is necessary for instances that need direct internet access.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 modify-subnet-attribute \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --map-public-ip-on-launch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will enable the Auto-assign Public IP feature for the public subnet identified by the &lt;code&gt;$AWS_PUBLIC_SUBNET&lt;/code&gt;variable. This feature tells the AWS to automatically assign a public IP to the instances launched in this subnet.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth noting that, you can also assign public IP addresses to instances by using Elastic IP addresses, a feature that allows you to allocate an IP address to your AWS account and then associate it with an instance. The advantage of Elastic IP addresses is that they can be moved between instances or be released when no longer needed, avoiding the extra charges that come with using an automatically assigned public IP address.&lt;/p&gt;
&lt;h3&gt;Step 5: Create an Internet Gateway&lt;/h3&gt;
&lt;p&gt;In this step, we will create an Internet Gateway and associate it with our VPC. An Internet Gateway is a VPC component that allows communication between instances in our VPC and the internet. This is a necessary step for our public subnet instances to have internet access.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_INTERNET_GATEWAY=$(aws ec2 create-internet-gateway \
  --query &amp;#39;InternetGateway.InternetGatewayId&amp;#39; \
  --output text)

aws ec2 create-tags \
  --resources $AWS_INTERNET_GATEWAY \
  --tags Key=Name,Value=internet-gateway

aws ec2 attach-internet-gateway \
  --vpc-id $AWS_VPC \
  --internet-gateway-id $AWS_INTERNET_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create an Internet Gateway, create a name tag for it and attach it to the VPC identified by the &lt;code&gt;$AWS_VPC&lt;/code&gt; variable. The Internet Gateway ID is stored in the variable &lt;code&gt;$AWS_INTERNET_GATEWAY&lt;/code&gt; for future reference.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth noting that, Internet Gateways are stateful, meaning that if a request initiated from your VPC is sent to an Internet Gateway, the response will be routed back to the source. On the other hand, a Virtual Private Gateway is stateless, meaning that it routes traffic but does not hold connection state. It&amp;#39;s important to choose the correct type of gateway depending on your use case.&lt;/p&gt;
&lt;h3&gt;Step 6: Create a Elastic IP&lt;/h3&gt;
&lt;p&gt;In this step, we will create a Elastic IP, which is a static public IPv4 address that can be allocated to your AWS account and then associated with an instance. Having a Elastic IP address allows you to mask the failure of an instance by rapidly remapping the address to another instance. This is useful when instances fail or if you want to change instances while keeping the same IP address.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_ELASTIC_IP=$(aws ec2 allocate-address \
  --domain vpc \
  --query &amp;#39;AllocationId&amp;#39; \
  --output text)

aws ec2 create-tags \
  --resources $AWS_ELASTIC_IP \
  --tags Key=Name,Value=elastic-ip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will allocate a new Elastic IP for your AWS account, and create a name tag for it. The Elastic IP address is stored in the variable &lt;code&gt;$AWS_ELASTIC_IP&lt;/code&gt; for future reference.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth noting that, Elastic IP addresses are charged for hourly usage when not associated with a running instance or when associated with a stopped instance or an unattached network interface. so, if you&amp;#39;re not using it make sure you release it to avoid any charges.&lt;/p&gt;
&lt;h3&gt;Step 7: Create a NAT Gateway&lt;/h3&gt;
&lt;p&gt;In this step, we will create a NAT Gateway and associate it with our VPC. A NAT Gateway allows instances in a private subnet to access the internet without exposing their private IP address. It is a highly available, managed service that allows outbound internet traffic from instances in a private subnet in your virtual private cloud (VPC). This is a necessary step for our private subnet instances to have internet access.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_NAT_GATEWAY=$(aws ec2 create-nat-gateway \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --allocation-id $AWS_ELASTIC_IP \
  --query &amp;#39;NatGateway.NatGatewayId&amp;#39; \
  --output text)

aws ec2 create-tags \
  --resources $AWS_NAT_GATEWAY \
  --tags Key=Name,Value=nat-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create a NAT Gateway, associated it with the public subnet identified by the &lt;code&gt;$AWS_PUBLIC_SUBNET&lt;/code&gt; variable, and using the Elastic IP that we allocated previously identified by &lt;code&gt;$AWS_ELASTIC_IP&lt;/code&gt;, also, it will create a name tag for it. The NAT Gateway ID is stored in the variable &lt;code&gt;$AWS_NAT_GATEWAY&lt;/code&gt; for future reference.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth noting that, the NAT Gateway requires a pre-allocated Elastic IP in order to be created, and this Elastic IP is consumed by the NAT Gateway and will not be available for other uses. Also, the NAT Gateway is a managed service, which means that AWS will take care of the maintenance and availability of the NAT Gateway, so you don&amp;#39;t have to worry about it.&lt;/p&gt;
&lt;h3&gt;Step 8: Create a Public and a Private Route Table&lt;/h3&gt;
&lt;p&gt;In this step, we will create two route tables: one public and one private. A route table contains a set of rules, called routes, that are used to determine where network traffic is directed. By creating separate route tables for our public and private subnets, we can ensure that traffic is routed correctly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_PUBLIC_ROUTE_TABLE=$(aws ec2 create-route-table \
  --vpc-id $AWS_VPC \
  --query &amp;#39;RouteTable.RouteTableId&amp;#39; \
  --output text)

AWS_PRIVATE_ROUTE_TABLE=$(aws ec2 create-route-table \
  --vpc-id $AWS_VPC \
  --query &amp;#39;RouteTable.RouteTableId&amp;#39; \
  --output text)

aws ec2 create-tags \
  --resources $AWS_PUBLIC_ROUTE_TABLE \
  --tags Key=Name,Value=public-route-table

aws ec2 create-tags \
  --resources $AWS_PRIVATE_ROUTE_TABLE \
  --tags Key=Name,Value=private-route-table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create two route tables associated with the VPC identified by the $AWS_VPC variable and create names for them &amp;quot;public-route-table&amp;quot; and &amp;quot;private-route-table&amp;quot; and will store the route table IDs in the variables &lt;code&gt;$AWS_PUBLIC_ROUTE_TABLE&lt;/code&gt;and&lt;code&gt;$AWS_PRIVATE_ROUTE_TABLE&lt;/code&gt; respectively for future reference.&lt;/p&gt;
&lt;h3&gt;Step 9: Create a Route in the Public Route Table for Internet Gateway&lt;/h3&gt;
&lt;p&gt;In this step, we will create a route in the public route table that directs all traffic to the Internet Gateway. This is necessary for instances in the public subnet to have internet access.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 create-route \
  --route-table-id $AWS_PUBLIC_ROUTE_TABLE \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id $AWS_INTERNET_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create a route in the public route table that directs all traffic (destination CIDR block 0.0.0.0/0) to the Internet Gateway identified by the &lt;code&gt;$AWS_INTERNET_GATEWAY&lt;/code&gt; variable. This will allow instances in the public subnet to access the internet.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth noting that, when you create a route in a route table, the route is propagated to all associated subnets, so it is important to make sure that you are creating the route in the correct route table.&lt;/p&gt;
&lt;h3&gt;Step 10: Create a Route in the Private Route Table for NAT Gateway&lt;/h3&gt;
&lt;p&gt;In this step, we will create a route in the private route table that directs all traffic to the NAT Gateway. This is necessary for instances in the private subnet to have internet access without exposing their private IP addresses.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 create-route \
  --route-table-id $AWS_PRIVATE_ROUTE_TABLE \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id $AWS_NAT_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create a route in the private route table that directs all traffic (destination CIDR block 0.0.0.0/0) to the NAT Gateway identified by the &lt;code&gt;$AWS_NAT_GATEWAY&lt;/code&gt; variable. This will allow instances in the private subnet to access the internet without exposing their private IP addresses.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth noting that, It is important that instances in the private subnet are not able to initiate direct internet access. This will help to protect your instances from malicious Internet traffic and also reduce the risk of accidental data leaks.&lt;/p&gt;
&lt;h3&gt;Step 11: Associate the Subnets with the Route Tables&lt;/h3&gt;
&lt;p&gt;In this step, we will associate the public and private subnets with the corresponding public and private route tables. This will ensure that traffic is routed correctly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 associate-route-table \
  --route-table-id $AWS_PUBLIC_ROUTE_TABLE \
  --subnet-id $AWS_PUBLIC_SUBNET

aws ec2 associate-route-table \
  --route-table-id $AWS_PRIVATE_ROUTE_TABLE \
  --subnet-id $AWS_PRIVATE_SUBNET
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will associate the public subnet identified by the &lt;code&gt;$AWS_PUBLIC_SUBNET&lt;/code&gt; variable with the public route table identified by the &lt;code&gt;$AWS_PUBLIC_ROUTE_TABLE&lt;/code&gt; variable, and the private subnet identified by the &lt;code&gt;$AWS_PRIVATE_SUBNET&lt;/code&gt; variable with the private route table identified by the &lt;code&gt;$AWS_PRIVATE_ROUTE_TABLE&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;This ensures that traffic is directed to the correct destination based on the subnet it originates from, by this way, traffic originating from the public subnet will be directed to the Internet Gateway and traffic originating from the private subnet will be directed to the NAT Gateway, this ensures that instances in the public subnet have internet access, and instances in the private subnet have internet access without exposing their private IP addresses.&lt;/p&gt;
&lt;h3&gt;Step 12: Create Security Groups&lt;/h3&gt;
&lt;p&gt;In this step, we will create security groups for the bastion host and the instances in the private subnet. Security groups act as a virtual firewall for your instances, controlling inbound and outbound traffic.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_BASTION_SECURITY_GROUP=$(aws ec2 create-security-group \
  --group-name bastion-security-group \
  --description &amp;quot;Security group for the bastion host&amp;quot; \
  --vpc-id $AWS_VPC \
  --query &amp;#39;GroupId&amp;#39; \
  --output text)

AWS_PRIVATE_SECURITY_GROUP=$(aws ec2 create-security-group \
  --group-name private-security-group \
  --description &amp;quot;Security group for the private instances&amp;quot; \
  --vpc-id $AWS_VPC \
  --query &amp;#39;GroupId&amp;#39; \
  --output text)

aws ec2 create-tags \
  --resources $AWS_BASTION_SECURITY_GROUP \
  --tags Key=Name,Value=bastion-security-group

aws ec2 create-tags \
  --resources $AWS_PRIVATE_SECURITY_GROUP \
  --tags Key=Name,Value=private-security-group

aws ec2 authorize-security-group-ingress \
  --group-id $AWS_BASTION_SECURITY_GROUP \
  --protocol tcp \
  --port 22 \
  --cidr 0.0.0.0/0 \
  --output text

aws ec2 authorize-security-group-ingress \
  --group-id $AWS_PRIVATE_SECURITY_GROUP \
  --protocol tcp \
  --port 22 \
  --source-group $AWS_BASTION_SECURITY_GROUP \
  --output text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create two security groups: one for the bastion host, and one for the instances in the private subnet.&lt;/p&gt;
&lt;p&gt;The security group for the bastion host is named &amp;quot;bastion-security-group&amp;quot;, and it is associated with the VPC identified by the &lt;code&gt;$AWS_VPC&lt;/code&gt; variable. It allows inbound traffic on port 22 (SSH) from any IP address (CIDR block 0.0.0.0/0) and It is useful to connect to instances via the bastion host.&lt;/p&gt;
&lt;p&gt;The security group for the instances in the private subnet is named &amp;quot;private-security-group&amp;quot;, and it is also associated with the VPC identified by the &lt;code&gt;$AWS_VPC&lt;/code&gt; variable. It allows all inbound traffic from the security group for the bastion host only, this way, instances in the private subnet can only be accessed via the bastion host and only from instances that are within the security group for the bastion host.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth noting that, These security groups will help ensure that only authorized traffic can reach your instances, and that traffic from your instances to the Internet is properly restricted.&lt;/p&gt;
&lt;h2&gt;Create a Two EC2 Instances&lt;/h2&gt;
&lt;p&gt;In this step, we will create two EC2 instances: one for the bastion host and one for the private subnet. Before creating these instances, you need to create an ssh key pair that will be used to access the instances via ssh.&lt;/p&gt;
&lt;h3&gt;Step 1: Create a Key Pair&lt;/h3&gt;
&lt;p&gt;In order to connect to the instances via SSH, you will need to create a Key Pair that will be used to authenticate the connection. To create a Key Pair, you can use the AWS Management Console, AWS CLI or SDKs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_KEY_PAIR=aws-key-pair
aws ec2 create-key-pair \
  --key-name $AWS_KEY_PAIR \
  --query &amp;#39;KeyMaterial&amp;#39; \
  --output text &amp;gt; $AWS_KEY_PAIR.pem
chmod 400 $AWS_KEY_PAIR.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create a new key pair named &lt;code&gt;aws-key-pair&lt;/code&gt; and the private key will be saved in the file &lt;code&gt;aws-key-pair.pem&lt;/code&gt; . Make sure to keep this file safe and secure, as it allows you to connect to the instances. The &lt;code&gt;chmod 400&lt;/code&gt; command will restrict the permissions on the key pair file so that it is only readable by the owner.&lt;/p&gt;
&lt;p&gt;Also, you may want to consider using environment variables for the key pair name, this way you can easily change the key pair name without having to search and replace it in the script.&lt;/p&gt;
&lt;h3&gt;Step 2: Get the latest AMI ID for Amazon Linux 2&lt;/h3&gt;
&lt;p&gt;Before launching an EC2 instance, we need to know the Amazon Machine Image (AMI) ID for the specific Operating System we want to use, in this case Amazon Linux 2. The AMI ID is used to specify the image for the instance when it&amp;#39;s being created. Instead of hard coding the AMI ID, it&amp;#39;s better to programmatically find the latest available AMI ID for the specific Operating System to ensure that the script will always use the latest version of the AMI.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the latest AMI ID for Amazon Linux 2
AWS_AMI=$(aws ec2 describe-images \
  --owners &amp;#39;amazon&amp;#39; \
  --filters &amp;#39;Name=name,Values=amzn2-ami-hvm-2.0.*&amp;#39; \
  &amp;#39;Name=state,Values=available&amp;#39; \
  --query &amp;#39;sort_by(Images, &amp;amp;CreationDate)[-1].[ImageId]&amp;#39; \
  --output &amp;#39;text&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will get the latest available Amazon Linux 2 AMI ID based on the filters provided. The &lt;code&gt;--owners&lt;/code&gt; option specifies that the AMI should be owned by Amazon. The &lt;code&gt;--filters&lt;/code&gt; option is used to filter the images returned by the describe-images command. The &lt;code&gt;Name=name,Values=amzn2-ami-hvm-2.0.*&lt;/code&gt; filter will return only the images that have a name that starts &lt;code&gt;with amzn2-ami-hvm-2.0&lt;/code&gt;. The &lt;code&gt;Name=state,Values=available&lt;/code&gt; filter will return only the images that are in the available state.&lt;/p&gt;
&lt;h3&gt;Step 3: Create a Bastion Host&lt;/h3&gt;
&lt;p&gt;In this step, we will use the &lt;code&gt;run-instances&lt;/code&gt; command to launch an EC2 instance for our Bastion host. The Bastion host will be used as a jump server to securely access the instances in the private subnet.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_BASTION_HOST=$(aws ec2 run-instances \
  --image-id $AWS_AMI \
  --count 1 \
  --instance-type t2.micro \
  --key-name $AWS_KEY_PAIR \
  --security-group-ids $AWS_BASTION_SECURITY_GROUP \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --associate-public-ip-address \
  --query &amp;#39;Instances[0].InstanceId&amp;#39; \
  --output text)

aws ec2 create-tags \
  --resources $AWS_BASTION_HOST \
  --tags Key=Name,Value=bastion-host
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create a single EC2 instance in the public subnet with the provided AMI ID and Key Pair, will be associated with the security group that we created earlier for the Bastion host, and it will be assigned a public IP address so that it can be accessed over the internet.&lt;/p&gt;
&lt;p&gt;The tag specifications was added to assign the Name value to the created instances.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also worth to note that you should consider to specify the availability zone, this way you can ensure that the instances are created in the availability zone that meets your requirements (i.e. the availability zone should have enough capacity to meet the instances requirements, etc.)&lt;/p&gt;
&lt;h3&gt;Step 4: Create a Private Host&lt;/h3&gt;
&lt;p&gt;In this step, we will use the run-instances command to launch an EC2 instance for our Private host. The private host will be running in a private subnet and it will not have public IP address.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_PRIVATE_HOST=$(aws ec2 run-instances \
  --image-id $AWS_AMI \
  --count 1 \
  --instance-type t2.micro \
  --key-name $AWS_KEY_PAIR \
  --security-group-ids $AWS_PRIVATE_SECURITY_GROUP \
  --subnet-id $AWS_PRIVATE_SUBNET \
  --query &amp;#39;Instances[0].InstanceId&amp;#39; \
  --output text)

aws ec2 create-tags \
  --resources $AWS_PRIVATE_HOST \
  --tags Key=Name,Value=private-host
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create a single EC2 instance in the private subnet with the provided AMI ID and Key Pair, will be associated with the security group that we created earlier for the private host, and it will not be assigned a public IP address.&lt;/p&gt;
&lt;p&gt;As the bastion host will act as the gateway to access the instances in private subnet via ssh.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also worth to note that you should consider to specify the availability zone, this way you can ensure that the instances are created in the availability zone that meets your requirements (i.e. the availability zone should have enough capacity to meet the instances requirements, etc.)&lt;/p&gt;
&lt;h2&gt;Connect to the Private Host&lt;/h2&gt;
&lt;p&gt;In this section, we will show you how to connect to the Private host using the Bastion host as a jump server.&lt;/p&gt;
&lt;h3&gt;Step 1: Get the Public IP Address of the Bastion Host&lt;/h3&gt;
&lt;p&gt;To connect to the private host, we first need to know the public IP address of the Bastion host. We can use the &lt;code&gt;describe-instances&lt;/code&gt; command to get the public IP address of the Bastion host.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_BASTION_HOST_PUBLIC_IP=$(aws ec2 describe-instances \
  --instance-ids $AWS_BASTION_HOST \
  --query &amp;#39;Reservations[0].Instances[0].PublicIpAddress&amp;#39; \
  --output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will get the public IP address of the Bastion host based on the instance ID.&lt;/p&gt;
&lt;p&gt;Once you have the public IP address of the Bastion host, you can use it to establish an SSH connection to the Bastion host.&lt;/p&gt;
&lt;h3&gt;Step 2: Connect to the Bastion Host&lt;/h3&gt;
&lt;p&gt;To connect to the Bastion Host, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ssh -i $AWS_KEY_PAIR.pem ec2-user@$AWS_BASTION_HOST_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will connect to the Bastion host using the key pair that we created earlier, and the public IP address of the Bastion host.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0034-how-to-setup-bastion-host-on-aws-using-aws-cli/connect-to-the-bastion-host.png&quot; alt=&quot;Connect to the Bastion Host&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Step 3: Get the Private IP Address of the Private Host&lt;/h3&gt;
&lt;p&gt;To connect to the private host via the Bastion host, we will need to know the private IP address of the private host. We can use the describe-instances command to get the private IP address of the private host.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_PRIVATE_HOST_PRIVATE_IP=$(aws ec2 describe-instances \
  --instance-ids $AWS_PRIVATE_HOST \
  --query &amp;#39;Reservations[0].Instances[0].PrivateIpAddress&amp;#39; \
  --output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will get the private IP address of the private host based on the instance ID and the output will be a text with the private ip address, you can use it in the next step.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth to note that you could also use the Name tag that we created earlier to retrieve the private IP address using the &lt;code&gt;--filters&lt;/code&gt; option, this way you can get the private IP address of the private host without knowing the instance ID.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_PRIVATE_HOST_PRIVATE_IP=$(aws ec2 describe-instances \
  --filters &amp;quot;Name=tag:Name,Values=private-host&amp;quot; \
  --query &amp;#39;Reservations[0].Instances[0].PrivateIpAddress&amp;#39; \
  --output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Connect to the Private Host&lt;/h3&gt;
&lt;p&gt;Once you have the private IP address of the private host, you can use the following command to connect to the private host via the Bastion host:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# add the private key
vi ~/.ssh/private-key.pem

# change the permission of the private key
chmod 400 ~/.ssh/private-key.pem

# connect to the private host
ssh -i ~/.ssh/private-key.pem ec2-user@$AWS_PRIVATE_HOST_PRIVATE_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will connect to the private host using the private key that we created earlier, and the private IP address of the private host.&lt;/p&gt;
&lt;h3&gt;Step 5: Check the Internet Connectivity&lt;/h3&gt;
&lt;p&gt;Now that you are connected to the private host, you can check if the host has internet connectivity by pinging a public IP or URL:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ping -c 4 google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will send 4 ICMP echo requests to the IP address of Google&amp;#39;s website, and the private host will respond with 4 ICMP echo replies if it can reach the internet. This verifies that the NAT gateway and route tables are configured correctly.&lt;/p&gt;
&lt;p&gt;Alternatively, you can also check internet connectivity by using curl command to download a webpage:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0034-how-to-setup-bastion-host-on-aws-using-aws-cli/internet-connectivity.png&quot; alt=&quot;Internet Connectivity&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl -s https://www.mkabumattar.com | head -n 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will download the website&amp;#39;s source code and will return it to the terminal, and check if the response is received from the website. If the private host has internet connectivity, it will show the webpage&amp;#39;s source code.&lt;/p&gt;
&lt;p&gt;It is important to note that, if you are running these commands from the bastion host, you might not face the same restrictions as the private host, in that case you should run the commands from the private host, or you could use a specific website for the test that is blocked for your private network&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0034-how-to-setup-bastion-host-on-aws-using-aws-cli/internet-connectivity-2.png&quot; alt=&quot;Internet Connectivity&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we walked through the process of creating a Bastion host on AWS using the AWS CLI. We created a VPC, subnets, an Internet gateway, a NAT gateway, route tables, security groups, and two EC2 instances. We then connected to the private host via the Bastion host and verified internet connectivity on the private host.&lt;/p&gt;
&lt;p&gt;It is important to note that this is just a basic setup, you might want to improve your security by using a more secure authentication method other than the key pair, such as IAM roles and SSM session manager, also you should consider adding extra logging, auditing, and monitoring to your setup.&lt;/p&gt;
&lt;p&gt;Thank you for reading this tutorial and I hope you found it useful. If you have any questions or feedback, feel free to leave a comment below.&lt;/p&gt;
&lt;h2&gt;Cleanup&lt;/h2&gt;
&lt;p&gt;When you are finished using the resources created in this tutorial, you should clean them up to avoid incurring unnecessary charges.&lt;/p&gt;
&lt;p&gt;You can use the AWS Management Console, or the AWS CLI to delete the resources.&lt;/p&gt;
&lt;Notice type=&quot;note&quot;&gt;
  Be careful when running the following commands, as they will delete the
  resources created in this tutorial
&lt;/Notice&gt;&lt;h3&gt;Delete the EC2 Instances&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 terminate-instances --instance-ids $AWS_BASTION_HOST $AWS_PRIVATE_HOST
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will delete the two EC2 instances created in this tutorial.&lt;/p&gt;
&lt;h3&gt;Detach and Delete Internet Gateway&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 detach-internet-gateway --internet-gateway-id $AWS_INTERNET_GATEWAY --vpc-id $AWS_VPC
aws ec2 delete-internet-gateway --internet-gateway-id $AWS_INTERNET_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will detach and delete the Internet gateway created in this tutorial.&lt;/p&gt;
&lt;h3&gt;Delete Route Tables&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 delete-route-table --route-table-id $AWS_PUBLIC_ROUTE_TABLE
aws ec2 delete-route-table --route-table-id $AWS_PRIVATE_ROUTE_TABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will delete the route tables created in this tutorial.&lt;/p&gt;
&lt;h3&gt;Delete NAT Gateway&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Wait for NAT Gateway to be deleted if it&amp;#39;s in &amp;#39;deleting&amp;#39; state
aws ec2 wait nat-gateway-deleted --nat-gateway-ids $AWS_NAT_GATEWAY
aws ec2 delete-nat-gateway --nat-gateway-id $AWS_NAT_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will delete the NAT gateway created in this tutorial.&lt;/p&gt;
&lt;h3&gt;Delete Elastic IP&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Ensure $AWS_ELASTIC_IP holds the AllocationId for release-address
# If $AWS_ELASTIC_IP was set to the PublicIp string, you&amp;#39;d need the AllocationId
# Assuming $AWS_ELASTIC_IP was set using:
# AWS_ELASTIC_IP_ALLOC_ID=$(aws ec2 allocate-address --domain vpc --query &amp;#39;AllocationId&amp;#39; --output text)
# Then use:
# aws ec2 release-address --allocation-id $AWS_ELASTIC_IP_ALLOC_ID
# If $AWS_ELASTIC_IP was set to the PublicIp string, this command might not work as expected.
# For the script in the article, $AWS_ELASTIC_IP stores AllocationId, so the original command is fine.
aws ec2 release-address --allocation-id $AWS_ELASTIC_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Delete Subnets&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 delete-subnet --subnet-id $AWS_PUBLIC_SUBNET
aws ec2 delete-subnet --subnet-id $AWS_PRIVATE_SUBNET
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will delete the subnets created in this tutorial.&lt;/p&gt;
&lt;h3&gt;Delete Security Groups&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 delete-security-group --group-id $AWS_BASTION_SECURITY_GROUP
aws ec2 delete-security-group --group-id $AWS_PRIVATE_SECURITY_GROUP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will delete the security groups created in this tutorial.&lt;/p&gt;
&lt;h3&gt;Delete VPC&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 delete-vpc --vpc-id $AWS_VPC
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Delete Key Pair&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws ec2 delete-key-pair --key-name $AWS_KEY_PAIR
rm -f $AWS_KEY_PAIR.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will delete the key pair created in this tutorial and also the key file from the local system.&lt;/p&gt;
&lt;p&gt;It is important to note that some resources may take a while to be fully deleted and some resources are dependent on others, so you may need to run the deletion commands multiple times and in a specific order.&lt;/p&gt;
&lt;p&gt;Also, you should check if there are any other resources that were created outside of the scope of this tutorial but are still associated with the VPC, subnet, security groups, and key pairs, and delete them as well.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS Command Line Interface (CLI) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&quot;&gt;Amazon Virtual Private Cloud (VPC) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html&quot;&gt;Security Groups for your VPC - Amazon VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html&quot;&gt;NAT Gateways - Amazon VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html&quot;&gt;Internet Gateways - Amazon VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html&quot;&gt;AWS Key Pairs and Amazon EC2 Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/quickstart/architecture/linux-bastion/&quot;&gt;Linux Bastion Hosts on AWS (Quick Start Reference Deployment)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html&quot;&gt;What is an Elastic IP address? - Amazon EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html&quot;&gt;Connect to your Linux instance using SSH - Amazon EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-vpc.html&quot;&gt;AWS CLI Command Reference - ec2 create-vpc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/run-instances.html&quot;&gt;AWS CLI Command Reference - ec2 run-instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/welcome.html&quot;&gt;AWS Well-Architected Framework - Security Pillar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>AWS CLI</category><category>Security</category><category>Networking</category><category>DevOps</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0034-how-to-setup-bastion-host-on-aws-using-aws-cli/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Setup Jenkins on AWS Using CloudFormation</title><link>https://mkabumattar.com/blog/post/how-to-setup-jenkins-on-aws-using-cloudformation/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-setup-jenkins-on-aws-using-cloudformation/</guid><description>We will be using CloudFormation to setup Jenkins on AWS. CloudFormation is a service that helps you model and set up your AWS resources so that you can spend less time managing those resources and more time focusing on your applications that run in AWS.</description><pubDate>Sun, 11 Dec 2022 22:43:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In a previous blog post, we setup Jenkins on AWS using the AWS CLI (&lt;a href=&quot;/blog/post/how-to-install-jenkins-on-aws-ec2-instance&quot;&gt;How to Install Jenkins on AWS EC2 Instance&lt;/a&gt;). In this blog post, we will be using CloudFormation to setup Jenkins on AWS. CloudFormation is a service that helps you model and set up your AWS resources so that you can spend less time managing those resources and more time focusing on your applications that run on AWS.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI installed and configured&lt;/li&gt;
&lt;li&gt;IAM user with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonVPCFullAccess&lt;/li&gt;
&lt;li&gt;AmazonEC2FullAccess&lt;/li&gt;
&lt;li&gt;AmazonS3FullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create a CloudFormation&lt;/h2&gt;
&lt;h3&gt;Step 1: Create a Key Pair&lt;/h3&gt;
&lt;p&gt;Create a key pair to access the EC2 instance via SSH.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a key pair
aws ec2 create-key-pair \
  --key-name jenkins-server-key-pair \
  --query &amp;#39;KeyMaterial&amp;#39; \
  --output text &amp;gt; jenkins-server-key-pair.pem

# Change the permission of the key pair
chmod 400 jenkins-server-key-pair.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;Notice type=&quot;note&quot;&gt;
  Store the key pair at a safe place. You will need it to access the EC2
  instance via SSH.
&lt;/Notice&gt;&lt;h3&gt;Step 2: Create a CloudFormation Template&lt;/h3&gt;
&lt;p&gt;Create a file named &lt;code&gt;jenkins-server.yml&lt;/code&gt; and add the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch jenkins-server.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;AWSTemplateFormatVersion: 2010-09-09
Description: &amp;gt;-
  This template creates a VPC with a public subnet and an EC2 instance with
  Jenkins installed. The EC2 instance is accessible via SSH and HTTP.

Parameters:
  VPCCidrBlock:
    Description: CIDR block for the VPC
    Type: String
    Default: 15.0.0.0/16
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  VPCName:
    Description: Name of the VPC
    Type: String
    Default: jenkins-server-vpc
    AllowedPattern: ^[a-zA-Z0-9-]*$
    ConstraintDescription: must be a valid VPC name.
  PublicSubnetCidrBlock:
    Description: CIDR block for the public subnet
    Type: String
    Default: 15.0.1.0/24
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  PublicSubnetAvailabilityZone:
    Description: Availability zone for the public subnet
    Type: String
    Default: us-east-1a
  PublicSubnetName:
    Description: Name of the public subnet
    Type: String
    Default: jenkins-server-public-subnet
    AllowedPattern: ^[a-zA-Z0-9-]*$
    ConstraintDescription: must be a valid subnet name.
  InternetGatewayName:
    Description: Name of the internet gateway
    Type: String
    Default: jenkins-server-internet-gateway
    AllowedPattern: ^[a-zA-Z0-9-]*$
    ConstraintDescription: must be a valid internet gateway name.
  PublicRouteTableName:
    Description: Name of the public route table
    Type: String
    Default: jenkins-server-public-route-table
    AllowedPattern: ^[a-zA-Z0-9-]*$
    ConstraintDescription: must be a valid route table name.
  SecurityGroupName:
    Description: Name of the security group
    Type: String
    Default: jenkins-server-security-group
    AllowedPattern: ^[a-zA-Z0-9-]*$
    ConstraintDescription: must be a valid security group name.
  KeyPairName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instances
    Type: AWS::EC2::KeyPair::KeyName
    Default: jenkins-server-key-pair
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  InstanceImageId:
    Description: Image ID of the instance
    Type: String
    Default: ami-0b0dcb5067f052a63
    AllowedPattern: ami-[a-z0-9]*
    ConstraintDescription: must be a valid AMI ID.
  InstanceType:
    Description: Enter the instance type for the instance
    Type: String
    Default: t2.micro
    AllowedValues:
      - t1.micro
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - m1.small
      - m1.medium
      - m1.large
      - m1.xlarge
      - m2.xlarge
      - m2.2xlarge
      - m2.4xlarge
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - c1.medium
      - c1.xlarge
      - c3.large
      - c3.xlarge
      - c3.2xlarge
      - c3.4xlarge
      - c3.8xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - g2.2xlarge
      - g2.8xlarge
      - r3.large
      - r3.xlarge
      - r3.2xlarge
      - r3.4xlarge
      - r3.8xlarge
      - i2.xlarge
      - i2.2xlarge
      - i2.4xlarge
      - i2.8xlarge
      - d2.xlarge
      - d2.2xlarge
      - d2.4xlarge
      - d2.8xlarge
      - hi1.4xlarge
      - hs1.8xlarge
      - cr1.8xlarge
      - cc2.8xlarge
      - cg1.4xlarge
    ConstraintDescription: must be a valid EC2 instance type.
  InstanceName:
    Description: Name of the instance
    Type: String
    Default: jenkins-server-instance
    AllowedPattern: ^[a-zA-Z0-9-]*$
    ConstraintDescription: must be a valid instance name.
  ElasticIPAddressName:
    Description: Name of the elastic IP address
    Type: String
    Default: jenkins-server-elastic-ip
    AllowedPattern: ^[a-zA-Z0-9-]*$
    ConstraintDescription: must be a valid elastic IP address name.

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCidrBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Ref VPCName
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PublicSubnetCidrBlock
      AvailabilityZone: !Ref PublicSubnetAvailabilityZone
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Ref PublicSubnetName
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Ref InternetGatewayName
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Ref PublicRouteTableName
  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Jenkins
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Ref SecurityGroupName
  Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref InstanceImageId
      InstanceType: !Ref InstanceType
      KeyName: !Ref KeyPairName
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref PublicSubnet
          GroupSet:
            - !Ref SecurityGroup
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          sudo yum update -y
          sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
          sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
          sudo yum upgrade
          sudo amazon-linux-extras install java-openjdk11 -y
          sudo yum install jenkins -y
          sudo systemctl start jenkins
          sudo systemctl enable jenkins
          sudo yum install git -y
      Tags:
        - Key: Name
          Value: !Ref InstanceName
  ElasticIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      NetworkBorderGroup: !Ref AWS::Region
      Tags:
        - Key: Name
          Value: !Ref ElasticIPAddressName
  ElasticIPAssociation:
    Type: AWS::EC2::EIPAssociation
    Properties:
      InstanceId: !Ref Instance
      EIP: !Ref ElasticIP

Mappings:
  AWSRegionArch2AMI:
    us-east-1:
      HVM64: ami-0b69ea66ff7391e80
      HVMG2: ami-0b69ea66ff7391e80
    us-east-2:
      HVM64: ami-0b69ea66ff7391e80
      HVMG2: ami-0b69ea66ff7391e80

Outputs:
  GetJenkinsDashboard:
    Description: URL to use for Jenkins dashboard
    Value: !Join
      - &amp;#39;&amp;#39;
      - - &amp;#39;http://&amp;#39;
        - !GetAtt Instance.PublicDnsName
        - &amp;#39;:8080&amp;#39;
  GitHubWebhookURL:
    Description: URL to use for GitHub webhooks
    Value: !Join
      - &amp;#39;&amp;#39;
      - - &amp;#39;http://&amp;#39;
        - !GetAtt Instance.PublicDnsName
        - &amp;#39;:8080/github-webhook/&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Create a CloudFormation Stack&lt;/h3&gt;
&lt;p&gt;Now that you have created a template, you can create a stack using the AWS CLI.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws cloudformation create-stack \
    --stack-name jenkins-server \
    --template-body file://jenkins-server.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Check the Status of the Stack&lt;/h3&gt;
&lt;p&gt;You can check the status of the stack using the AWS CLI.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws cloudformation describe-stacks \
    --stack-name jenkins-server
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 5: Access the Jenkins Server&lt;/h3&gt;
&lt;p&gt;You can access the Jenkins server using the public IP address of the instance.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the public IP address of the Jenkins server instance
AWS_PUBLIC_IP=$(aws ec2 describe-instances \
  --filters &amp;quot;Name=tag:Name,Values=jenkins-server-instance&amp;quot; \
  --query &amp;quot;Reservations[*].Instances[*].PublicIpAddress&amp;quot; \
  --output text)

# Open the Jenkins dashboard in the browser
echo &amp;quot;http://${AWS_PUBLIC_IP}:8080&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Connect to the Jenkins Server, and Setup Jenkins&lt;/h2&gt;
&lt;h3&gt;Step 1: Connect to the Jenkins Server&lt;/h3&gt;
&lt;p&gt;Connect to the Jenkins server using SSH.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the public IP address of the Jenkins server instance
AWS_PUBLIC_IP=$(aws ec2 describe-instances \
  --filters &amp;quot;Name=tag:Name,Values=jenkins-server-instance&amp;quot; \
  --query &amp;quot;Reservations[*].Instances[*].PublicIpAddress&amp;quot; \
  --output text)

# Connect to the Jenkins server instance via SSH
ssh -i jenkins-server-key-pair.pem ec2-user@${AWS_PUBLIC_IP}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 6: Configure Jenkins&lt;/h3&gt;
&lt;p&gt;Connect to EC2 instance using SSH and run the following commands to configure Jenkins.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo cat /var/lib/jenkins/secrets/initialAdminPassword
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0033-how-to-setup-jenkins-on-aws-using-cloudformation/jenkins-initial-password.png&quot; alt=&quot;jenkins-initial-password&quot;&gt;&lt;/p&gt;
&lt;p&gt;Copy the initial password and paste it in the Jenkins login page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0033-how-to-setup-jenkins-on-aws-using-cloudformation/jenkins-login.png&quot; alt=&quot;jenkins-login&quot;&gt;&lt;/p&gt;
&lt;p&gt;Select the recommended plugins and click on the Install button.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0033-how-to-setup-jenkins-on-aws-using-cloudformation/jenkins-install-plugins.png&quot; alt=&quot;jenkins-install-plugins&quot;&gt;&lt;/p&gt;
&lt;p&gt;Create an admin user and click on the Save and Finish button.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0033-how-to-setup-jenkins-on-aws-using-cloudformation/jenkins-create-admin-user.png&quot; alt=&quot;jenkins-create-admin-user&quot;&gt;&lt;/p&gt;
&lt;p&gt;Done! You have successfully setup Jenkins on AWS using CloudFormation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0033-how-to-setup-jenkins-on-aws-using-cloudformation/jenkins-dashboard.png&quot; alt=&quot;jenkins-dashboard&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Cleanup&lt;/h2&gt;
&lt;p&gt;You can delete the stack using the AWS CLI.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Delete the stack
aws cloudformation delete-stack \
    --stack-name jenkins-server

# Check the status of the stack
aws cloudformation describe-stacks \
    --stack-name jenkins-server

# Delete the key pair
aws ec2 delete-key-pair \
    --key-name jenkins-server-key-pair
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we have learned how to setup Jenkins on AWS using CloudFormation. We have also learned how to create a CloudFormation template and create a stack using the AWS CLI.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html&quot;&gt;AWS CloudFormation User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-reference.html&quot;&gt;AWS CloudFormation Template Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/&quot;&gt;Jenkins Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/&quot;&gt;Jenkins User Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/installing/&quot;&gt;Installing Jenkins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS Command Line Interface (CLI) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&quot;&gt;Amazon VPC User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html&quot;&gt;AWS Key Pairs and Amazon EC2 Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacks.html&quot;&gt;Working with AWS CloudFormation Stacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-userdata&quot;&gt;User data in CloudFormation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html&quot;&gt;Elastic IP addresses - Amazon EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/how-to-install-jenkins-on-aws-ec2-instance&quot;&gt;How to Install Jenkins on AWS EC2 Instance&lt;/a&gt; (Previous related post)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/devops/aws-cloudformation-best-practices/&quot;&gt;AWS CloudFormation Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>Jenkins</category><category>CloudFormation</category><category>DevOps</category><category>CI/CD</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0033-how-to-setup-jenkins-on-aws-using-cloudformation/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to CI/CD AWS With Github using Jenkins</title><link>https://mkabumattar.com/blog/post/how-to-ci-cd-aws-with-github-using-jenkins/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-ci-cd-aws-with-github-using-jenkins/</guid><description>In this post, I will show you how to setup a CI/CD pipeline using Jenkins and Github to deploy a simple PHP application to Devlopment and Production environments on AWS. With this setup, you can deploy your application to AWS with a single click.</description><pubDate>Wed, 07 Dec 2022 12:21:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In previous posts, I have shown you how to setup Jenkins on AWS EC2 instance. You can check the post &lt;a href=&quot;/blog/post/install-jenkins-on-aws-ec2-instance&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this post, I will show you how to setup a CI/CD pipeline using Jenkins and Github to deploy a simple PHP application to Devlopment and Production environments on AWS. With this setup, you can deploy your application to AWS with a single click.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI installed and configured&lt;/li&gt;
&lt;li&gt;IAM user with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonVPCFullAccess&lt;/li&gt;
&lt;li&gt;AmazonEC2FullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Setup AWS Infrastructure for Devlopment Environment&lt;/h2&gt;
&lt;h3&gt;Create VPC&lt;/h3&gt;
&lt;h4&gt;Step 1: Create VPC&lt;/h4&gt;
&lt;p&gt;To create a VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a VPC
AWS_VPC=$(aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --query &amp;#39;Vpc.VpcId&amp;#39; \
  --output text)

# Add a name tag to the VPC
aws ec2 create-tags \
  --resources $AWS_VPC \
  --tags Key=Name,Value=environments-vpc
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 2: Modify your custom VPC and enable DNS hostname support, and DNS support&lt;/h4&gt;
&lt;p&gt;To modify your custom VPC and enable DNS hostname support, and DNS support, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Modify your custom VPC and enable DNS hostname support, and DNS support
# Enable DNS hostnames
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-hostnames &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;

# Enable DNS support
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-support &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 3: Create a Public Subnet&lt;/h4&gt;
&lt;p&gt;To create a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a public subnet
AWS_PUBLIC_SUBNET=$(aws ec2 create-subnet \
  --vpc-id $AWS_VPC \
  --cidr-block 10.0.1.0/24 \
  --query &amp;#39;Subnet.SubnetId&amp;#39; \
  --output text)

# Add a name tag to the public subnet
aws ec2 create-tags \
  --resources $AWS_PUBLIC_SUBNET \
  --tags Key=Name,Value=environments-public-subnet
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 4: Enable Auto-assign Public IP on the subnet&lt;/h4&gt;
&lt;p&gt;To enable auto-assign public IP on the subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable auto-assign public IP on the subnet
aws ec2 modify-subnet-attribute \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --map-public-ip-on-launch
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 5: Create an Internet Gateway&lt;/h4&gt;
&lt;p&gt;To create an internet gateway, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an Internet Gateway
AWS_INTERNET_GATEWAY=$(aws ec2 create-internet-gateway \
  --query &amp;#39;InternetGateway.InternetGatewayId&amp;#39; \
  --output text)

# Add a name tag to the Internet Gateway
aws ec2 create-tags \
  --resources $AWS_INTERNET_GATEWAY \
  --tags Key=Name,Value=environments-internet-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 6: Attach the Internet Gateway to your VPC&lt;/h4&gt;
&lt;p&gt;To attach the internet gateway to your VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the Internet Gateway to the VPC
aws ec2 attach-internet-gateway \
  --internet-gateway-id $AWS_INTERNET_GATEWAY \
  --vpc-id $AWS_VPC
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 7: Create a Route Table&lt;/h4&gt;
&lt;p&gt;To create a route table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a route table
AWS_ROUTE_TABLE=$(aws ec2 create-route-table \
  --vpc-id $AWS_VPC \
  --query &amp;#39;RouteTable.RouteTableId&amp;#39; \
  --output text)

# Add a name tag to the route table
aws ec2 create-tags \
  --resources $AWS_ROUTE_TABLE \
  --tags Key=Name,Value=environments-route-table
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 8: Create a custom route table association&lt;/h4&gt;
&lt;p&gt;To create a route in the route table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a custom route table association
aws ec2 associate-route-table \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --route-table-id $AWS_ROUTE_TABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 9: Associate the subnet with route table, making it a public subnet&lt;/h4&gt;
&lt;p&gt;To associate the subnet with route table, making it a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the subnet with route table, making it a public subnet
aws ec2 create-route \
  --route-table-id $AWS_ROUTE_TABLE \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id $AWS_INTERNET_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 10: Create a Security Group&lt;/h4&gt;
&lt;p&gt;To create a security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a security group
AWS_SECURITY_GROUP=$(aws ec2 create-security-group \
  --group-name aws-security-group \
  --description &amp;quot;AWS Security Group&amp;quot; \
  --vpc-id $AWS_VPC \
  --query &amp;#39;GroupId&amp;#39; \
  --output text)

# Add a name tag to the security group
aws ec2 create-tags \
  --resources $AWS_SECURITY_GROUP \
  --tags Key=Name,Value=environments-security-group
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 11: Add inbound rules to the security group&lt;/h4&gt;
&lt;p&gt;To add inbound rules to the security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add inbound rules to the security group

# Add SSH rule
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 22 \
  --cidr 0.0.0.0/0 \
  --output text

# Add HTTP rule
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 80 \
  --cidr 0.0.0.0/0 \
  --output text

# Add HTTPS rule
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 443 \
  --cidr 0.0.0.0/0 \
  --output text
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a Two EC2 Instances&lt;/h3&gt;
&lt;h4&gt;Step 1: Get the latest AMI ID for Amazon Linux 2&lt;/h4&gt;
&lt;p&gt;To get the latest AMI ID for Amazon Linux 2, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the latest AMI ID for Amazon Linux 2
AWS_AMI=$(aws ec2 describe-images \
  --owners &amp;#39;amazon&amp;#39; \
  --filters &amp;#39;Name=name,Values=amzn2-ami-hvm-2.0.*&amp;#39; \
  &amp;#39;Name=state,Values=available&amp;#39; \
  --query &amp;#39;sort_by(Images, &amp;amp;CreationDate)[-1].[ImageId]&amp;#39; \
  --output &amp;#39;text&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 2: Create a Key Pair&lt;/h4&gt;
&lt;p&gt;To create a key pair, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a key pair
aws ec2 create-key-pair \
  --key-name aws-key-pair \
  --query &amp;#39;KeyMaterial&amp;#39; \
  --output text &amp;gt; aws-key-pair.pem

# Change the permission of the key pair
chmod 400 aws-key-pair.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 3: Create a user data script&lt;/h4&gt;
&lt;p&gt;To create a user data script, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a userdata script
cat &amp;lt;&amp;lt;EOF &amp;gt; userdata.sh
#!/bin/bash

# update the system
sudo yum update -y

# install httpd
sudo yum install -y httpd

# start httpd
sudo systemctl start httpd

# enable httpd
sudo systemctl enable httpd

# at first, we will enable amazon-linux-extras so that we can specify the PHP version that we want to install.
sudo amazon-linux-extras enable php7.4 -y

# install php
sudo yum install -y php php-{pear,cgi,common,curl,mbstring,gd,mysqlnd,gettext,bcmath,json,xml,fpm,intl,zip,imap}

# install MariaDB
sudo yum install -y mariadb-server

# start MariaDB
sudo systemctl start mariadb

# enable MariaDB
sudo systemctl enable mariadb

# we will now secure MariaDB.
sudo mysql_secure_installation &amp;lt;&amp;lt;EOF2
y
121612
121612
y
y
y
y
EOF2

# change the ownership of the /var/www directory to the apache user and group.
sudo chown -R apache:apache /var/www

# this will give read, write, and execute permissions to the owner, group, and others.
sudo chmod -R 775 /var/www

# this is for the wp-config.php file
sudo chmod -R 755 /var/www/html

# restart MariaDB
sudo systemctl restart mariadb

# restart httpd
sudo systemctl restart httpd
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 4: Create an EC2 instance&lt;/h4&gt;
&lt;p&gt;To create an EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an EC2 Instance
AWS_EC2_INSTANCE_PROD=$(aws ec2 run-instances \
  --image-id $AWS_AMI \
  --count 1 \
  --instance-type t2.micro \
  --key-name aws-key-pair \
  --security-group-ids $AWS_SECURITY_GROUP \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --user-data file://userdata.sh \
  --query &amp;#39;Instances[0].InstanceId&amp;#39; \
  --output text)

AWS_EC2_INSTANCE_DEV=$(aws ec2 run-instances \
  --image-id $AWS_AMI \
  --count 1 \
  --instance-type t2.micro \
  --key-name aws-key-pair \
  --security-group-ids $AWS_SECURITY_GROUP \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --user-data file://userdata.sh \
  --query &amp;#39;Instances[0].InstanceId&amp;#39; \
  --output text)


# Add a name tag to the EC2 Instance
aws ec2 create-tags \
  --resources $AWS_EC2_INSTANCE_PROD \
  --tags Key=Name,Value=environments-prod

aws ec2 create-tags \
  --resources $AWS_EC2_INSTANCE_DEV \
  --tags Key=Name,Value=environments-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 5: Create an Elastic IP&lt;/h4&gt;
&lt;p&gt;To create an Elastic IP, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an Elastic IP
AWS_ELASTIC_IP_PROD=$(aws ec2 allocate-address \
  --domain vpc \
  --query &amp;#39;AllocationId&amp;#39; \
  --output text)

AWS_ELASTIC_IP_DEV=$(aws ec2 allocate-address \
  --domain vpc \
  --query &amp;#39;AllocationId&amp;#39; \
  --output text)

# Add a name tag to the Elastic IP
aws ec2 create-tags \
  --resources $AWS_ELASTIC_IP_PROD \
  --tags Key=Name,Value=environments-prod

aws ec2 create-tags \
  --resources $AWS_ELASTIC_IP_DEV \
  --tags Key=Name,Value=environments-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 6: Associate the Elastic IP with the EC2 Instance&lt;/h4&gt;
&lt;p&gt;To associate the Elastic IP with the EC2 Instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the Elastic IP with the EC2 Instance
aws ec2 associate-address \
  --instance-id $AWS_EC2_INSTANCE_PROD \
  --allocation-id $AWS_ELASTIC_IP_PROD

aws ec2 associate-address \
  --instance-id $AWS_EC2_INSTANCE_DEV \
  --allocation-id $AWS_ELASTIC_IP_DEV
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 7: Get the Public IP Address of the EC2 Instance&lt;/h4&gt;
&lt;p&gt;To get the public IP address of the EC2 Instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the public IP address of the EC2 Instance
AWS_PUBLIC_IP_PROD=$(aws ec2 describe-instances \
  --instance-ids $AWS_EC2_INSTANCE_PROD \
  --query &amp;#39;Reservations[0].Instances[0].PublicIpAddress&amp;#39; \
  --output text)

AWS_PUBLIC_IP_DEV=$(aws ec2 describe-instances \
  --instance-ids $AWS_EC2_INSTANCE_DEV \
  --query &amp;#39;Reservations[0].Instances[0].PublicIpAddress&amp;#39; \
  --output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Setup Simple PHP Application&lt;/h2&gt;
&lt;h3&gt;Create a GitHub Repository&lt;/h3&gt;
&lt;h4&gt;Step 1: Create a GitHub repository&lt;/h4&gt;
&lt;p&gt;To create a GitHub repository, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a GitHub repository
curl -u $GITHUB_USERNAME https://api.github.com/user/repos -d &amp;#39;{&amp;quot;name&amp;quot;:&amp;quot;quick-test-jenkins&amp;quot;}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or you can create a repository from the GitHub website, go to &lt;a href=&quot;https://github.com/new&quot;&gt;Create a new repository&lt;/a&gt; and create a new repository.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Repository name: quick-test-jenkins&lt;/li&gt;
&lt;li&gt;Description: Quick Test Jenkins&lt;/li&gt;
&lt;li&gt;Public/Private: Private&lt;/li&gt;
&lt;li&gt;Initialize this repository with a README: No&lt;/li&gt;
&lt;li&gt;Add .gitignore: None&lt;/li&gt;
&lt;li&gt;Add a license: None&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 2: Clone the GitHub repository&lt;/h4&gt;
&lt;p&gt;To clone the GitHub repository, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Clone the GitHub repository
git clone git@github.com:MKAbuMattar/quick-test-jenkins.git

# Change directory
cd quick-test-jenkins
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 3: Create a new branch&lt;/h4&gt;
&lt;p&gt;To create a new branch, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a new branch
git checkout -b devlopment
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a Simple PHP Application&lt;/h3&gt;
&lt;h4&gt;Step 1: Create the structure of the application&lt;/h4&gt;
&lt;p&gt;To create the structure of the application, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create the structure of the application
mkdir -p app/{config,controllers,views} assets/{css}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 2: Create the &lt;code&gt;env.php&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;To create the &lt;code&gt;config.php&lt;/code&gt; file, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php:app/config/env.php&quot;&gt;&amp;lt;?php

// Define the environment
define(&amp;#39;URL&amp;#39;, $_SERVER[&amp;#39;HTTP_HOST&amp;#39;]);
define(&amp;#39;DEV_DNS&amp;#39;, &amp;#39;DEVLOPMENT_DNS&amp;#39;);
define(&amp;#39;PROD_DNS&amp;#39;, &amp;#39;PRODUCTION_DNS&amp;#39;);
define(&amp;#39;DEV&amp;#39;, &amp;#39;DEVLOPMENT_IP&amp;#39;);
define(&amp;#39;PROD&amp;#39;, &amp;#39;PRODUCTION_IP&amp;#39;);

// check the environment
if (URL == PROD_DNS || URL == PROD) {
    define(&amp;#39;ENV&amp;#39;, &amp;#39;PROD&amp;#39;);
} elseif (URL == DEV_DNS || URL == DEV) {
    define(&amp;#39;ENV&amp;#39;, &amp;#39;DEV&amp;#39;);
} else {
    define(&amp;#39;ENV&amp;#39;, &amp;#39;LOCAL&amp;#39;);
}


// Define the database
switch (ENV) {
  case &amp;#39;PROD&amp;#39;:
    define( &amp;#39;DB_NAME&amp;#39;, &amp;#39;PROD_PHP&amp;#39;);
    define( &amp;#39;DB_USER&amp;#39;, &amp;#39;PROD_USER&amp;#39; );
    define( &amp;#39;DB_PASSWORD&amp;#39;, &amp;#39;161216&amp;#39; );
    define( &amp;#39;DB_HOST&amp;#39;, &amp;#39;localhost&amp;#39; );
  break;
  case &amp;#39;DEV&amp;#39;:
    define( &amp;#39;DB_NAME&amp;#39;, &amp;#39;DEV_PHP&amp;#39;);
    define( &amp;#39;DB_USER&amp;#39;, &amp;#39;DEV_USER&amp;#39; );
    define( &amp;#39;DB_PASSWORD&amp;#39;, &amp;#39;121612&amp;#39; );
    define( &amp;#39;DB_HOST&amp;#39;, &amp;#39;localhost&amp;#39; );
  break;
  default:
    define( &amp;#39;DB_NAME&amp;#39;, &amp;#39;&amp;#39;);
    define( &amp;#39;DB_USER&amp;#39;, &amp;#39;&amp;#39; );
    define( &amp;#39;DB_PASSWORD&amp;#39;, &amp;#39;&amp;#39; );
    define( &amp;#39;DB_HOST&amp;#39;, &amp;#39;&amp;#39; );
  break;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 3: Create the &lt;code&gt;connection.php&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;To create the &lt;code&gt;connection.php&lt;/code&gt; file, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php:app/config/connection.php&quot;&gt;&amp;lt;?php

// Include the env.php file
require_once &amp;#39;env.php&amp;#39;;

// Create a connection to the database
try {
  $conn = new PDO(&amp;quot;mysql:host=&amp;quot;.DB_HOST.&amp;quot;;dbname=&amp;quot;.DB_NAME, DB_USER, DB_PASSWORD);
  $conn-&amp;gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
  echo &amp;quot;Connection failed: &amp;quot; . $e-&amp;gt;getMessage();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 4: Create the controller file&lt;/h4&gt;
&lt;p&gt;To create the controller file, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php:app/controllers/index.php&quot;&gt;&amp;lt;?php

// Include the connection.php file
require_once &amp;#39;app/config/connection.php&amp;#39;;

// Get the data from the database
$query = &amp;quot;SELECT * FROM `users`&amp;quot;;
$stmt = $conn-&amp;gt;prepare($query);
$stmt-&amp;gt;execute();
$users = $stmt-&amp;gt;fetchAll(PDO::FETCH_ASSOC);

// close the connection
$conn = null;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 5: Create the view file&lt;/h4&gt;
&lt;p&gt;To create the view file, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php:app/views/index.php&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot; /&amp;gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1&amp;quot; /&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;?php echo ENV; ?&amp;gt; | My Site&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;./assets/css/normalize.css&amp;quot; /&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;./assets/css/main.css&amp;quot; /&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;header&amp;gt;
      &amp;lt;h1&amp;gt;My Site&amp;lt;/h1&amp;gt;

      &amp;lt;nav&amp;gt;
        &amp;lt;ul&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;./index.php&amp;quot;&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/nav&amp;gt;
    &amp;lt;/header&amp;gt;

    &amp;lt;main&amp;gt;
      &amp;lt;h2&amp;gt;Home&amp;lt;/h2&amp;gt;
      &amp;lt;p&amp;gt;Welcome to my site!&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;
        &amp;lt;?php echo &amp;quot;Environment: &amp;quot; . ENV; ?&amp;gt;
      &amp;lt;/p&amp;gt;
    &amp;lt;/main&amp;gt;

    &amp;lt;footer&amp;gt;
      &amp;lt;p&amp;gt;My Site &amp;amp;copy; 2022&amp;lt;/p&amp;gt;
    &amp;lt;/footer&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 6: Create the &lt;code&gt;index.php&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;To create the &lt;code&gt;index.php&lt;/code&gt; file, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php:index.php&quot;&gt;&amp;lt;?php

// Include the controller file
require_once &amp;#39;app/controllers/index.php&amp;#39;;

// Include the view file
require_once &amp;#39;app/views/index.php&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 7: Create the &lt;code&gt;normalize.css&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;To create the &lt;code&gt;normalize.css&lt;/code&gt; file, run the following command:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to see the code of the `normalize.css` file&lt;/summary&gt;&lt;pre&gt;&lt;code class=&quot;language-css:assets/css/normalize.css&quot;&gt;/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */

/* Document
   ========================================================================== */

/**
 * 1. Correct the line height in all browsers.
 * 2. Prevent adjustments of font size after orientation changes in iOS.
 */

html {
  line-height: 1.15; /* 1 */
  -webkit-text-size-adjust: 100%; /* 2 */
}

/* Sections
   ========================================================================== */

/**
 * Remove the margin in all browsers.
 */

body {
  margin: 0;
}

/**
 * Render the `main` element consistently in IE.
 */

main {
  display: block;
}

/**
 * Correct the font size and margin on `h1` elements within `section` and
 * `article` contexts in Chrome, Firefox, and Safari.
 */

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

/* Grouping content
   ========================================================================== */

/**
 * 1. Add the correct box sizing in Firefox.
 * 2. Show the overflow in Edge and IE.
 */

hr {
  box-sizing: content-box; /* 1 */
  height: 0; /* 1 */
  overflow: visible; /* 2 */
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */

pre {
  font-family: monospace, monospace; /* 1 */
  font-size: 1em; /* 2 */
}

/* Text-level semantics
   ========================================================================== */

/**
 * Remove the gray background on active links in IE 10.
 */

a {
  background-color: transparent;
}

/**
 * 1. Remove the bottom border in Chrome 57-
 * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
 */

abbr[title] {
  border-bottom: none; /* 1 */
  text-decoration: underline; /* 2 */
  text-decoration: underline dotted; /* 2 */
}

/**
 * Add the correct font weight in Chrome, Edge, and Safari.
 */

b,
strong {
  font-weight: bolder;
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */

code,
kbd,
samp {
  font-family: monospace, monospace; /* 1 */
  font-size: 1em; /* 2 */
}

/**
 * Add the correct font size in all browsers.
 */

small {
  font-size: 80%;
}

/**
 * Prevent `sub` and `sup` elements from affecting the line height in
 * all browsers.
 */

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

/* Embedded content
   ========================================================================== */

/**
 * Remove the border on images inside links in IE 10.
 */

img {
  border-style: none;
}

/* Forms
   ========================================================================== */

/**
 * 1. Change the font styles in all browsers.
 * 2. Remove the margin in Firefox and Safari.
 */

button,
input,
optgroup,
select,
textarea {
  font-family: inherit; /* 1 */
  font-size: 100%; /* 1 */
  line-height: 1.15; /* 1 */
  margin: 0; /* 2 */
}

/**
 * Show the overflow in IE.
 * 1. Show the overflow in Edge.
 */

button,
input {
  /* 1 */
  overflow: visible;
}

/**
 * Remove the inheritance of text transform in Edge, Firefox, and IE.
 * 1. Remove the inheritance of text transform in Firefox.
 */

button,
select {
  /* 1 */
  text-transform: none;
}

/**
 * Correct the inability to style clickable types in iOS and Safari.
 */

button,
[type=&amp;quot;button&amp;quot;],
[type=&amp;quot;reset&amp;quot;],
[type=&amp;quot;submit&amp;quot;] {
  -webkit-appearance: button;
}

/**
 * Remove the inner border and padding in Firefox.
 */

button::-moz-focus-inner,
[type=&amp;quot;button&amp;quot;]::-moz-focus-inner,
[type=&amp;quot;reset&amp;quot;]::-moz-focus-inner,
[type=&amp;quot;submit&amp;quot;]::-moz-focus-inner {
  border-style: none;
  padding: 0;
}

/**
 * Restore the focus styles unset by the previous rule.
 */

button:-moz-focusring,
[type=&amp;quot;button&amp;quot;]:-moz-focusring,
[type=&amp;quot;reset&amp;quot;]:-moz-focusring,
[type=&amp;quot;submit&amp;quot;]:-moz-focusring {
  outline: 1px dotted ButtonText;
}

/**
 * Correct the padding in Firefox.
 */

fieldset {
  padding: 0.35em 0.75em 0.625em;
}

/**
 * 1. Correct the text wrapping in Edge and IE.
 * 2. Correct the color inheritance from `fieldset` elements in IE.
 * 3. Remove the padding so developers are not caught out when they zero out
 *    `fieldset` elements in all browsers.
 */

legend {
  box-sizing: border-box; /* 1 */
  color: inherit; /* 2 */
  display: table; /* 1 */
  max-width: 100%; /* 1 */
  padding: 0; /* 3 */
  white-space: normal; /* 1 */
}

/**
 * Add the correct vertical alignment in Chrome, Firefox, and Opera.
 */

progress {
  vertical-align: baseline;
}

/**
 * Remove the default vertical scrollbar in IE 10+.
 */

textarea {
  overflow: auto;
}

/**
 * 1. Add the correct box sizing in IE 10.
 * 2. Remove the padding in IE 10.
 */

[type=&amp;quot;checkbox&amp;quot;],
[type=&amp;quot;radio&amp;quot;] {
  box-sizing: border-box; /* 1 */
  padding: 0; /* 2 */
}

/**
 * Correct the cursor style of increment and decrement buttons in Chrome.
 */

[type=&amp;quot;number&amp;quot;]::-webkit-inner-spin-button,
[type=&amp;quot;number&amp;quot;]::-webkit-outer-spin-button {
  height: auto;
}

/**
 * 1. Correct the odd appearance in Chrome and Safari.
 * 2. Correct the outline style in Safari.
 */

[type=&amp;quot;search&amp;quot;] {
  -webkit-appearance: textfield; /* 1 */
  outline-offset: -2px; /* 2 */
}

/**
 * Remove the inner padding in Chrome and Safari on macOS.
 */

[type=&amp;quot;search&amp;quot;]::-webkit-search-decoration {
  -webkit-appearance: none;
}

/**
 * 1. Correct the inability to style clickable types in iOS and Safari.
 * 2. Change font properties to `inherit` in Safari.
 */

::-webkit-file-upload-button {
  -webkit-appearance: button; /* 1 */
  font: inherit; /* 2 */
}

/* Interactive
   ========================================================================== */

/*
 * Add the correct display in Edge, IE 10+, and Firefox.
 */

details {
  display: block;
}

/*
 * Add the correct display in all browsers.
 */

summary {
  display: list-item;
}

/* Misc
   ========================================================================== */

/**
 * Add the correct display in IE 10+.
 */

template {
  display: none;
}

/**
 * Add the correct display in IE 10.
 */

[hidden] {
  display: none;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h4&gt;Step 8: Create the &lt;code&gt;main.css&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;To create the &lt;code&gt;main.css&lt;/code&gt; file, run the following command:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the code of the `main.css` file&lt;/summary&gt;&lt;pre&gt;&lt;code class=&quot;language-css:assets/css/main.css&quot;&gt;* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

html {
  scroll-behavior: smooth;
  font-size: 62.5%;
}

body {
  font-family: &amp;quot;Roboto&amp;quot;, sans-serif;
  font-size: 1.6rem;
  line-height: 1.6;
  color: #333;
}

header {
  display: flex;
  justify-content: space-around;
  align-items: center;
  background-color: #333;
  color: #fff;
  height: 10rem;
}

header &amp;gt; nav {
  display: flex;
  justify-content: space-around;
  align-items: center;
  width: 50%;
}

header &amp;gt; nav &amp;gt; ul {
  display: flex;
  justify-content: space-around;
  align-items: center;
  width: 100%;
}

header &amp;gt; nav &amp;gt; ul &amp;gt; li {
  list-style: none;
}

header &amp;gt; nav &amp;gt; ul &amp;gt; li &amp;gt; a {
  text-decoration: none;
  color: #fff;
}

main {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  height: 70vh;
}

main &amp;gt; h1 {
  font-size: 5rem;
  margin-bottom: 2rem;
}

main &amp;gt; p {
  font-size: 2rem;
  margin-bottom: 2rem;
}

footer {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 10rem;
  background-color: #333;
  color: #fff;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h4&gt;Step 8: Add the files to the GitHub repository&lt;/h4&gt;
&lt;p&gt;To add the files to the GitHub repository, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add the files to the GitHub repository
git add .

# Commit the files to the GitHub repository
git commit -m &amp;quot;build: add the files to the GitHub repository&amp;quot;

# Push the files to the GitHub repository
git push origin devlopment
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a Jenkins Pipeline&lt;/h3&gt;
&lt;h4&gt;Step 1: Create a new Jenkins pipeline&lt;/h4&gt;
&lt;p&gt;To create a new Jenkins pipeline, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a new Jenkins pipeline
touch Jenkinsfile
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 2: Add the code to the Jenkins pipeline&lt;/h4&gt;
&lt;p&gt;To add the code to the Jenkins pipeline, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy:Jenkinsfile&quot;&gt;pipeline {
  agent any
  environment {
    AWS_PUBLIC_IP_DEV = &amp;#39;AWS_PUBLIC_IP_DEV&amp;#39;
  }

  stages {
    stage(&amp;#39;Deploy to Development&amp;#39;) {
      steps {
        sh &amp;#39;&amp;#39;&amp;#39;
          # remove the files
          ssh -i &amp;quot;/var/lib/jenkins/.ssh/aws-key-pair.pem&amp;quot; -o StrictHostKeyChecking=no ec2-user@${AWS_PUBLIC_IP_DEV} &amp;quot;sudo rm -rf /var/www/html/*&amp;quot;
          # copy the files to the dev server
          scp -i &amp;quot;/var/lib/jenkins/.ssh/aws-key-pair.pem&amp;quot; -o StrictHostKeyChecking=no -r ./* ec2-user@${AWS_PUBLIC_IP_DEV}:/var/www/html
          # restart the apache server
          ssh -i &amp;quot;/var/lib/jenkins/.ssh/aws-key-pair.pem&amp;quot; -o StrictHostKeyChecking=no ec2-user@${AWS_PUBLIC_IP_DEV} &amp;quot;sudo systemctl restart httpd&amp;quot;
        &amp;#39;&amp;#39;&amp;#39;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 3: Add the files to the GitHub repository&lt;/h4&gt;
&lt;p&gt;To add the files to the GitHub repository, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add the files to the GitHub repository
git add .

# Commit the files to the GitHub repository
git commit -m &amp;quot;build: add the jenkins pipeline to the GitHub repository&amp;quot;

# Push the files to the GitHub repository
git push origin devlopment
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a Jenkins Job&lt;/h3&gt;
&lt;h4&gt;Step 1: Create a new Jenkins job&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Open the Jenkins dashboard at EC2 instance from previous blog post. Go to &lt;code&gt;http://&amp;lt;public-ip-address&amp;gt;:8080/&lt;/code&gt; and login with the credentials you created in the previous blog post.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-dashboard.png&quot; alt=&quot;Jenkins dashboard&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Click on &lt;code&gt;New Item&lt;/code&gt; and enter the name of the job. Select &lt;code&gt;Pipeline&lt;/code&gt; and click on &lt;code&gt;OK&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;Quick Test Jenkins Devlopment&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Select: &lt;code&gt;Pipeline&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click on: &lt;code&gt;OK&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-new-item.png&quot; alt=&quot;Jenkins new item&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Configure the job.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Description: &lt;code&gt;Quick Test Jenkins Devlopment&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Select: &lt;code&gt;Pipeline&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Definition: &lt;code&gt;Pipeline script from SCM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;SCM: &lt;code&gt;Git&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Repository URL: &lt;code&gt;https://github.com/MKAbuMattar/quick-test-jenkins.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Credentials: &lt;code&gt;Add&lt;/code&gt; &amp;gt; &lt;code&gt;Jenkins&lt;/code&gt; &amp;gt; &lt;code&gt;Global credentials (unrestricted)&lt;/code&gt; &amp;gt; &lt;code&gt;Add Credentials&lt;/code&gt; &amp;gt; &lt;code&gt;Username with password&lt;/code&gt; &amp;gt; &lt;code&gt;Kind: Username with password&lt;/code&gt; &amp;gt; &lt;code&gt;Username: &amp;lt;your-github-username&amp;gt;&lt;/code&gt; &amp;gt; &lt;code&gt;Password: &amp;lt;your-github-password&amp;gt;&lt;/code&gt; &amp;gt; &lt;code&gt;ID: &amp;lt;your-github-username&amp;gt;&lt;/code&gt; &amp;gt; &lt;code&gt;Description: &amp;lt;your-github-username&amp;gt;&lt;/code&gt; &amp;gt; &lt;code&gt;OK&lt;/code&gt; &amp;gt; &lt;code&gt;OK&lt;/code&gt; &amp;gt; &lt;code&gt;OK&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Branches to build: &lt;code&gt;*/devlopment&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click on: &lt;code&gt;Save&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; How to Add Git Credentials in Jenkins for private repositories on GitHub&lt;/p&gt;
&lt;/blockquote&gt;
&lt;iframe
  width=&quot;100%&quot;
  height=&quot;515&quot;
  src=&quot;https://www.youtube.com/embed/HSA_mZoADSw&quot;
  title=&quot;How to Add Git Credentials in Jenkins&quot;
  frameborder=&quot;0&quot;
  allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
  allowfullscreen
&gt;&lt;/iframe&gt;&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-configure-job.png&quot; alt=&quot;Jenkins configure job&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Step 2: Build the Jenkins job&lt;/h4&gt;
&lt;p&gt;Before building the Jenkins job, you need to add the key pair to the Jenkins server.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connect to the Jenkins server using SSH.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Connect to the Jenkins server using SSH
ssh -i &amp;quot;&amp;lt;path-to-key-pair&amp;gt;&amp;quot; ec2-user@&amp;lt;public-ip-address&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Login to the Jenkins server.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Login to the Jenkins server
sudo -su jenkins
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Create a &lt;code&gt;.ssh&lt;/code&gt; directory.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a .ssh directory
mkdir .ssh

# Change the directory
cd .ssh
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Create a &lt;code&gt;aws-key-pair.pem&lt;/code&gt; file.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a aws-key-pair.pem file
cat &amp;gt; aws-key-pair.pem &amp;lt;&amp;lt; EOF
-----BEGIN RSA PRIVATE KEY-----
copy the private key from the key pair
-----END RSA PRIVATE KEY-----
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Change the permission of the &lt;code&gt;aws-key-pair.pem&lt;/code&gt; file.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the permission of the aws-key-pair.pem file
chmod 400 aws-key-pair.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Exit the Jenkins server.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Exit the Jenkins server
exit
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Click on &lt;code&gt;Build Now&lt;/code&gt; to build the Jenkins job.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-build-now.png&quot; alt=&quot;Jenkins build now&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Click on &lt;code&gt;Console Output&lt;/code&gt; to see the build logs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-console-output.png&quot; alt=&quot;Jenkins console output&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Step 3: Build the Jenkins job Automatically on GitHub push&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Go to &lt;code&gt;GitHub&lt;/code&gt; &amp;gt; go to &lt;code&gt;quick-test-jenkins&lt;/code&gt; repository&lt;ul&gt;
&lt;li&gt;Click on &lt;code&gt;Settings&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Click on &lt;code&gt;Webhooks&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Click on &lt;code&gt;Add webhook&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Payload URL: &lt;code&gt;http://&amp;lt;public-ip-address&amp;gt;:8080/github-webhook/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Content type: &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Which events would you like to trigger this webhook?: &lt;code&gt;Just the push event.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Active: &lt;code&gt;Yes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click on: &lt;code&gt;Add webhook&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/github-add-webhook.png&quot; alt=&quot;GitHub add webhook&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to &lt;code&gt;Jenkins&lt;/code&gt; &amp;gt; &lt;code&gt;Quick Test Jenkins Devlopment&lt;/code&gt; job&lt;ul&gt;
&lt;li&gt;Click on &lt;code&gt;Configure&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Select: &lt;code&gt;GitHub hook trigger for GITScm polling&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click on: &lt;code&gt;Save&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-configure-job-2.png&quot; alt=&quot;Jenkins configure job&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Step 4: Test the Jenkins job Automatically on GitHub push&lt;/h4&gt;
&lt;p&gt;We&amp;#39;ll add new files to the &lt;code&gt;devlopment&lt;/code&gt; branch and push them to the GitHub repository.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php:app/views/tabs.php&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot; /&amp;gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1&amp;quot; /&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;?php echo ENV; ?&amp;gt; | My Site&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;./assets/css/normalize.css&amp;quot; /&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;./assets/css/main.css&amp;quot; /&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;header&amp;gt;
      &amp;lt;h1&amp;gt;My Site&amp;lt;/h1&amp;gt;

      &amp;lt;nav&amp;gt;
        &amp;lt;ul&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;./index.php&amp;quot;&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;./table.php&amp;quot;&amp;gt;Table&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/nav&amp;gt;
    &amp;lt;/header&amp;gt;

    &amp;lt;main&amp;gt;
      &amp;lt;h2&amp;gt;Home&amp;lt;/h2&amp;gt;
      &amp;lt;p&amp;gt;Welcome to my site!&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;
        &amp;lt;?php echo &amp;quot;Environment: &amp;quot; . ENV; ?&amp;gt;
      &amp;lt;/p&amp;gt;

      &amp;lt;table border=&amp;quot;1&amp;quot;&amp;gt;
        &amp;lt;thead&amp;gt;
          &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;ID&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Email&amp;lt;/th&amp;gt;
          &amp;lt;/tr&amp;gt;
        &amp;lt;/thead&amp;gt;
        &amp;lt;tbody&amp;gt;
          &amp;lt;?php foreach ($users as $user) : ?&amp;gt;
            &amp;lt;tr&amp;gt;
              &amp;lt;td&amp;gt;&amp;lt;?php echo $user[&amp;#39;id&amp;#39;]; ?&amp;gt;&amp;lt;/td&amp;gt;
              &amp;lt;td&amp;gt;&amp;lt;?php echo $user[&amp;#39;name&amp;#39;]; ?&amp;gt;&amp;lt;/td&amp;gt;
              &amp;lt;td&amp;gt;&amp;lt;?php echo $user[&amp;#39;email&amp;#39;]; ?&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
          &amp;lt;?php endforeach; ?&amp;gt;
        &amp;lt;/tbody&amp;gt;
      &amp;lt;/table&amp;gt;
    &amp;lt;/main&amp;gt;

    &amp;lt;footer&amp;gt;
      &amp;lt;p&amp;gt;My Site &amp;amp;copy; 2022&amp;lt;/p&amp;gt;
    &amp;lt;/footer&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-php:app/views/index.php&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot; /&amp;gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1&amp;quot; /&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;?php echo ENV; ?&amp;gt; | My Site&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;./assets/css/normalize.css&amp;quot; /&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;./assets/css/main.css&amp;quot; /&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;header&amp;gt;
      &amp;lt;h1&amp;gt;My Site&amp;lt;/h1&amp;gt;

      &amp;lt;nav&amp;gt;
        &amp;lt;ul&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;./index.php&amp;quot;&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;./table.php&amp;quot;&amp;gt;Table&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/nav&amp;gt;
    &amp;lt;/header&amp;gt;

    &amp;lt;main&amp;gt;
      &amp;lt;h2&amp;gt;Home&amp;lt;/h2&amp;gt;
      &amp;lt;p&amp;gt;Welcome to my site!&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;
        &amp;lt;?php echo &amp;quot;Environment: &amp;quot; . ENV; ?&amp;gt;
      &amp;lt;/p&amp;gt;
    &amp;lt;/main&amp;gt;

    &amp;lt;footer&amp;gt;
      &amp;lt;p&amp;gt;My Site &amp;amp;copy; 2022&amp;lt;/p&amp;gt;
    &amp;lt;/footer&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-php:table.php&quot;&gt;&amp;lt;?php

// Include the controller file
require_once &amp;#39;app/controllers/index.php&amp;#39;;

// Include the view file
require_once &amp;#39;app/views/tabs.php&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before we push the files to the GitHub repository, we&amp;#39;ll open the EC2 instance in the browser to see the changes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/ec2-instance-2.png&quot; alt=&quot;EC2 instance&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add the files to the GitHub repository
git add .

# Commit the files to the GitHub repository
git commit -m &amp;quot;build: test the Jenkins job Automatically on GitHub push&amp;quot;

# Push the files to the GitHub repository
git push origin devlopment
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/github-push.png&quot; alt=&quot;GitHub push&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;code&gt;Jenkins&lt;/code&gt; &amp;gt; &lt;code&gt;Quick Test Jenkins Devlopment&lt;/code&gt; job &amp;gt; &lt;code&gt;Build History&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-build-history-2.png&quot; alt=&quot;Jenkins build history&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Click on &lt;code&gt;Build #2&lt;/code&gt; to see the build details.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-build-details-2.png&quot; alt=&quot;Jenkins build details&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Open the EC2 instance in the browser to see the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/ec2-instance-3.png&quot; alt=&quot;EC2 instance&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Step 5: We&amp;#39;ll do the Same Changes for &lt;code&gt;Jenkinsfile&lt;/code&gt; file&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# create a new directory
mkdir -p .build

# create a new directory for development and production
mkdir -p .build/dev .build/prod

# move the Jenkinsfile file to the development directory
mv Jenkinsfile .build/dev

# create a new Jenkinsfile file for production
touch .build/prod/Jenkinsfile
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy:.build/prod/Jenkinsfile&quot;&gt;pipeline {
  agent any
  environment {
    AWS_PUBLIC_IP_PROD = &amp;#39;&amp;#39;
  }

  stages {
    stage(&amp;#39;Deploy to Production&amp;#39;) {
      steps {
        sh &amp;#39;&amp;#39;&amp;#39;
          # remove the files
          ssh -i &amp;quot;/var/lib/jenkins/.ssh/aws-key-pair.pem&amp;quot; -o StrictHostKeyChecking=no ec2-user@${AWS_PUBLIC_IP_PROD} &amp;quot;sudo rm -rf /var/www/html/*&amp;quot;
          # copy the files to the prod server
          scp -i &amp;quot;/var/lib/jenkins/.ssh/aws-key-pair.pem&amp;quot; -o StrictHostKeyChecking=no -r ./* ec2-user@${AWS_PUBLIC_IP_PROD}:/var/www/html
          # restart the apache server
          ssh -i &amp;quot;/var/lib/jenkins/.ssh/aws-key-pair.pem&amp;quot; -o StrictHostKeyChecking=no ec2-user@${AWS_PUBLIC_IP_PROD} &amp;quot;sudo systemctl restart httpd&amp;quot;
        &amp;#39;&amp;#39;&amp;#39;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 6: Do Some Changes at Jenkins Configure for Development Jenkins Job&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;code&gt;Jenkins&lt;/code&gt; &amp;gt; &lt;code&gt;Quick Test Jenkins Devlopment&lt;/code&gt; job &amp;gt; &lt;code&gt;Configure&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Scroll down to &lt;code&gt;Script Path&lt;/code&gt; and change the value to &lt;code&gt;Jenkinsfile&lt;/code&gt; to &lt;code&gt;.build/dev/Jenkinsfile&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-configure-2.png&quot; alt=&quot;Jenkins configure&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Step 7: Setup the Production Jenkins job&lt;/h4&gt;
&lt;p&gt;the Production Jenkins job will be triggered automatically when the Development Jenkins job is successful merge to the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-dashboard-2.png&quot; alt=&quot;Jenkins dashboard&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Click on &lt;code&gt;New Item&lt;/code&gt; and enter the name of the job. Select &lt;code&gt;Pipeline&lt;/code&gt; and click on &lt;code&gt;OK&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;Quick Test Jenkins Production&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Select: &lt;code&gt;Pipeline&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click on: &lt;code&gt;OK&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-new-item-2.png&quot; alt=&quot;Jenkins new item&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Configure the job.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Description: &lt;code&gt;Quick Test Jenkins Production&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Select: &lt;code&gt;Poll SCM&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Schedule: &lt;code&gt;H/5 * * * *&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Select: &lt;code&gt;Ignore post-commit hooks&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Select: &lt;code&gt;Pipeline&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Definition: &lt;code&gt;Pipeline script from SCM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;SCM: &lt;code&gt;Git&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Repository URL: &lt;code&gt;https://github.com/MKAbuMattar/quick-test-jenkins.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Credentials: &lt;code&gt;Add&lt;/code&gt; &amp;gt; &lt;code&gt;Jenkins&lt;/code&gt; &amp;gt; &lt;code&gt;Global credentials (unrestricted)&lt;/code&gt; &amp;gt; &lt;code&gt;Add Credentials&lt;/code&gt; &amp;gt; &lt;code&gt;Username with password&lt;/code&gt; &amp;gt; &lt;code&gt;Kind: Username with password&lt;/code&gt; &amp;gt; &lt;code&gt;Username: &amp;lt;your-github-username&amp;gt;&lt;/code&gt; &amp;gt; &lt;code&gt;Password: &amp;lt;your-github-password&amp;gt;&lt;/code&gt; &amp;gt; &lt;code&gt;ID: &amp;lt;your-github-username&amp;gt;&lt;/code&gt; &amp;gt; &lt;code&gt;Description: &amp;lt;your-github-username&amp;gt;&lt;/code&gt; &amp;gt; &lt;code&gt;OK&lt;/code&gt; &amp;gt; &lt;code&gt;OK&lt;/code&gt; &amp;gt; &lt;code&gt;OK&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Branches to build: &lt;code&gt;*/main&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click on: &lt;code&gt;Save&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/jenkins-configure-job-3.png&quot; alt=&quot;Jenkins configure job&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Step 8: Go to GitHub and Merge the &lt;code&gt;devlopment&lt;/code&gt; branch to the &lt;code&gt;main&lt;/code&gt; branch&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;code&gt;GitHub&lt;/code&gt; &amp;gt; &lt;code&gt;quick-test-jenkins&lt;/code&gt; repository &amp;gt; &lt;code&gt;devlopment&lt;/code&gt; branch &amp;gt; &lt;code&gt;Pull requests&lt;/code&gt; &amp;gt; &lt;code&gt;New pull request&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/github-pull-request-2.png&quot; alt=&quot;GitHub pull request&quot;&gt;&lt;/p&gt;
&lt;p&gt;Check the EC2 instance in the browser to see the changes, and you&amp;#39;ll see the changes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/ec2-instance-4.png&quot; alt=&quot;EC2 instance&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/ec2-instance-5.png&quot; alt=&quot;EC2 instance&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to setup a CI/CD pipeline using Jenkins and GitHub. We also learned how to setup a Jenkins job to automatically deploy the code to the AWS EC2 instance.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/&quot;&gt;Jenkins User Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/syntax/&quot;&gt;Jenkins Pipeline Syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/webhooks&quot;&gt;GitHub Docs - Webhooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS Command Line Interface (CLI) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&quot;&gt;Amazon VPC User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/&quot;&gt;PHP Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/getting-started/&quot;&gt;Getting started with Jenkins Pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/using/managing-credentials/&quot;&gt;Managing Jenkins Credentials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html&quot;&gt;AWS EC2 Key Pairs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html&quot;&gt;User data and shell scripts for EC2 instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/install-jenkins-on-aws-ec2-instance&quot;&gt;Install Jenkins on AWS EC2 Instance&lt;/a&gt; (Previous related post)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://guides.github.com/introduction/git-handbook/&quot;&gt;Git Handbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/developer/guides/continuous-integration/&quot;&gt;Continuous Integration with Jenkins - Jenkins Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>CI/CD</category><category>DevOps</category><category>AWS</category><category>Jenkins</category><category>GitHub</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0032-how-to-ci-cd-aws-with-github-using-jenkins/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Install Jenkins on AWS EC2 Instance</title><link>https://mkabumattar.com/blog/post/install-jenkins-on-aws-ec2-instance/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/install-jenkins-on-aws-ec2-instance/</guid><description>In this post, I will show you how to Create an EC2 Instance on AWS and install Jenkins on it.</description><pubDate>Tue, 06 Dec 2022 18:43:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, I will show you how to Create an EC2 Instance on AWS and install Jenkins on it.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI installed and configured&lt;/li&gt;
&lt;li&gt;IAM user with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonVPCFullAccess&lt;/li&gt;
&lt;li&gt;AmazonEC2FullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create a VPC&lt;/h2&gt;
&lt;h3&gt;Step 1: Create a VPC&lt;/h3&gt;
&lt;p&gt;To create a VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a VPC
AWS_VPC=$(aws ec2 create-vpc \
  --cidr-block 15.0.0.0/16 \
  --query &amp;#39;Vpc.VpcId&amp;#39; \
  --output text)

# Add a name tag to the VPC
aws ec2 create-tags \
  --resources $AWS_VPC \
  --tags Key=Name,Value=jenkins-vpc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_VPC&lt;/code&gt; is a variable that holds the VPC ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr-block&lt;/code&gt; The IPv4 network range for the VPC, in CIDR notation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; The JMESPath query that is used to extract data from the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Modify your custom VPC and enable DNS hostname support, and DNS support&lt;/h3&gt;
&lt;p&gt;To modify your custom VPC and enable DNS hostname support, and DNS support, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Modify your custom VPC and enable DNS hostname support, and DNS support
# Enable DNS hostnames
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-hostnames &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;

# Enable DNS support
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-support &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--enable-dns-hostnames&lt;/code&gt; Indicates whether the instances launched in the VPC get DNS hostnames.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--enable-dns-support&lt;/code&gt; Indicates whether DNS resolution is supported for the VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Create a Public Subnet&lt;/h3&gt;
&lt;p&gt;To create a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a public subnet
AWS_PUBLIC_SUBNET=$(aws ec2 create-subnet \
  --vpc-id $AWS_VPC \
  --cidr-block 15.0.1.0/24 \
  --query &amp;#39;Subnet.SubnetId&amp;#39; \
  --output text)

# Add a name tag to the public subnet
aws ec2 create-tags \
  --resources $AWS_PUBLIC_SUBNET \
  --tags Key=Name,Value=jenkins-public-subnet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_PUBLIC_SUBNET&lt;/code&gt; is a variable that holds the public subnet ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr-block&lt;/code&gt; The IPv4 network range for the subnet, in CIDR notation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; The JMESPath query that is used to extract data from the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Enable Auto-assign Public IP on the subnet&lt;/h3&gt;
&lt;p&gt;To enable auto-assign public IP on the subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable auto-assign public IP on the subnet
aws ec2 modify-subnet-attribute \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --map-public-ip-on-launch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; The ID of the subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--map-public-ip-on-launch&lt;/code&gt; Indicates whether to assign a public IPv4 address to instances launched in the subnet.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Create an Internet Gateway&lt;/h3&gt;
&lt;p&gt;To create an internet gateway, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an internet gateway
AWS_INTERNET_GATEWAY=$(aws ec2 create-internet-gateway \
  --query &amp;#39;InternetGateway.InternetGatewayId&amp;#39; \
  --output text)

# Add a name tag to the internet gateway
aws ec2 create-tags \
  --resources $AWS_INTERNET_GATEWAY \
  --tags Key=Name,Value=jenkins-internet-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_INTERNET_GATEWAY&lt;/code&gt; is a variable that holds the internet gateway ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; The JMESPath query that is used to extract data from the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 6: Attach the Internet Gateway to the VPC&lt;/h3&gt;
&lt;p&gt;To attach the internet gateway to the VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the internet gateway to the VPC
aws ec2 attach-internet-gateway \
  --internet-gateway-id $AWS_INTERNET_GATEWAY \
  --vpc-id $AWS_VPC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--internet-gateway-id&lt;/code&gt; The ID of the internet gateway.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; The ID of the VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 7: Create a Route Table&lt;/h3&gt;
&lt;p&gt;To create a route table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a route table
AWS_ROUTE_TABLE=$(aws ec2 create-route-table \
  --vpc-id $AWS_VPC \
  --query &amp;#39;RouteTable.RouteTableId&amp;#39; \
  --output text)

# Add a name tag to the route table
aws ec2 create-tags \
  --resources $AWS_ROUTE_TABLE \
  --tags Key=Name,Value=jenkins-route-table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_ROUTE_TABLE&lt;/code&gt; is a variable that holds the route table ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; The JMESPath query that is used to extract data from the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 8: Create a custom route table association&lt;/h3&gt;
&lt;p&gt;To create a custom route table association, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a custom route table association
aws ec2 associate-route-table \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --route-table-id $AWS_ROUTE_TABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; The ID of the subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--route-table-id&lt;/code&gt; The ID of the route table.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 9: Associate the subnet with route table, making it a public subnet&lt;/h3&gt;
&lt;p&gt;To associate the subnet with route table, making it a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the subnet with route table, making it a public subnet
aws ec2 create-route \
  --route-table-id $AWS_ROUTE_TABLE \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id $AWS_INTERNET_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--route-table-id&lt;/code&gt; The ID of the route table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--destination-cidr-block&lt;/code&gt; The IPv4 CIDR address block used for the destination match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--gateway-id&lt;/code&gt; The ID of an internet gateway or virtual private gateway attached to your VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 10: Create a Security Group&lt;/h3&gt;
&lt;p&gt;To create a security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a security group
AWS_SECURITY_GROUP=$(aws ec2 create-security-group \
  --group-name aws-security-group \
  --description &amp;quot;AWS Security Group&amp;quot; \
  --vpc-id $AWS_VPC \
  --query &amp;#39;GroupId&amp;#39; \
  --output text)

# Add a name tag to the security group
aws ec2 create-tags \
  --resources $AWS_SECURITY_GROUP \
  --tags Key=Name,Value=jenkins-security-group
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_SECURITY_GROUP&lt;/code&gt; is a variable that holds the security group ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--group-name&lt;/code&gt; The name of the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--description&lt;/code&gt; A description for the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; The JMESPath query that is used to extract data from the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 11: Add a rule to the security group&lt;/h3&gt;
&lt;p&gt;To add a rule to the security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add a rule to the security group

# Add SSH rule
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 22 \
  --cidr 0.0.0.0/0 \
  --output text

# Add HTTP rule
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 80 \
  --cidr 0.0.0.0/0 \
  --output text

# Add HTTPS rule
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 443 \
  --cidr 0.0.0.0/0 \
  --output text

# Add Jenkins rule
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 8080-8090 \
  --cidr 0.0.0.0/0 \
  --output text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--group-id&lt;/code&gt; The ID of the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--protocol&lt;/code&gt; The IP protocol name or number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--port&lt;/code&gt; The port number or range of port numbers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr&lt;/code&gt; The IPv4 CIDR range.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create an EC2 Instance&lt;/h2&gt;
&lt;h3&gt;Step 1: Get the latest AMI ID&lt;/h3&gt;
&lt;p&gt;To get the latest AMI ID, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the latest AMI ID
AWS_AMI=$(aws ec2 describe-images \
  --owners &amp;#39;amazon&amp;#39; \
  --filters &amp;#39;Name=name,Values=amzn2-ami-hvm-2.0.*&amp;#39; \
  &amp;#39;Name=state,Values=available&amp;#39; \
  --query &amp;#39;sort_by(Images, &amp;amp;CreationDate)[-1].[ImageId]&amp;#39; \
  --output &amp;#39;text&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_AMI&lt;/code&gt; is a variable that holds the AMI ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--owners&lt;/code&gt; The AWS account ID of the owner.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--filters&lt;/code&gt; The filters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; The JMESPath query that is used to extract data from the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Create a Key Pair&lt;/h3&gt;
&lt;p&gt;To create a key pair, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a key pair
aws ec2 create-key-pair \
  --key-name aws-key-pair \
  --query &amp;#39;KeyMaterial&amp;#39; \
  --output text &amp;gt; aws-key-pair.pem

# Change the permission of the key pair
chmod 400 aws-key-pair.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--key-name&lt;/code&gt; The name of the key pair.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; The JMESPath query that is used to extract data from the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&lt;/code&gt; The output is redirected to a file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aws-key-pair.pem&lt;/code&gt; The name of the file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chmod 400 aws-key-pair.pem&lt;/code&gt; Change the permission of the key pair, so that only the owner can read and write.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Create a User Data Script&lt;/h3&gt;
&lt;p&gt;To create a user data script, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a user data script
cat &amp;lt;&amp;lt; EOF &amp;gt; user-data.sh
#!/bin/bash

# update the system
sudo yum update -y

# add the jenkins repo
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
sudo yum upgrade

# install java
sudo amazon-linux-extras install java-openjdk11 -y

# install jenkins
sudo yum install jenkins -y

# start jenkins
sudo systemctl start jenkins

# enable jenkins
sudo systemctl enable jenkins

# install git
sudo yum install git -y
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cat &amp;lt;&amp;lt; EOF &amp;gt; user-data.sh&lt;/code&gt; The output is redirected to a file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;user-data.sh&lt;/code&gt; The name of the file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#!/bin/bash&lt;/code&gt; The shebang line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo yum update -y&lt;/code&gt; Update the system.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo&lt;/code&gt; Add the Jenkins repo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key&lt;/code&gt; Import the Jenkins repo key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo yum upgrade&lt;/code&gt; Upgrade the system.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo amazon-linux-extras install java-openjdk11 -y&lt;/code&gt; Install Java.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo yum install jenkins -y&lt;/code&gt; Install Jenkins.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo systemctl start jenkins&lt;/code&gt; Start Jenkins.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo systemctl enable jenkins&lt;/code&gt; Enable Jenkins.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Create an EC2 Instance&lt;/h3&gt;
&lt;p&gt;To create an EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an EC2 instance
AWS_INSTANCE=$(aws ec2 run-instances \
--image-id $AWS_AMI \
--instance-type t2.micro \
--key-name aws-key-pair \
--monitoring &amp;quot;Enabled=false&amp;quot; \
--security-group-ids $AWS_SECURITY_GROUP \
--subnet-id $AWS_PUBLIC_SUBNET \
--user-data file://user-data.sh \
--query &amp;#39;Instances[0].InstanceId&amp;#39; \
--output text)

# add a name tag to the instance
aws ec2 create-tags \
  --resources $AWS_INSTANCE \
  --tags Key=Name,Value=jenkins-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_INSTANCE&lt;/code&gt; is a variable that holds the instance ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--image-id&lt;/code&gt; The ID of the AMI.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-type&lt;/code&gt; The instance type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-name&lt;/code&gt; The name of the key pair.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--monitoring&lt;/code&gt; The monitoring for the instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--security-group-ids&lt;/code&gt; The IDs of the security groups.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; The ID of the subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--user-data&lt;/code&gt; The user data to provide when launching the instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; The JMESPath query that is used to extract data from the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Create an Elastic IP&lt;/h3&gt;
&lt;p&gt;To create an Elastic IP, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an Elastic IP
AWS_ELASTIC_IP=$(aws ec2 allocate-address \
  --domain vpc \
  --query &amp;#39;AllocationId&amp;#39; \
  --output text)

# add a name tag to the Elastic IP
aws ec2 create-tags \
  --resources $AWS_ELASTIC_IP \
  --tags Key=Name,Value=jenkins-server-elastic-ip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_ELASTIC_IP&lt;/code&gt; is a variable that holds the Elastic IP ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--domain&lt;/code&gt; The domain name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; The JMESPath query that is used to extract data from the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 6: Associate the Elastic IP with the EC2 Instance&lt;/h3&gt;
&lt;p&gt;To associate the Elastic IP with the EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the Elastic IP with the EC2 instance
aws ec2 associate-address \
  --allocation-id $AWS_ELASTIC_IP \
  --instance-id $AWS_INSTANCE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--allocation-id&lt;/code&gt; The allocation ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-id&lt;/code&gt; The ID of the instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Connect to the Jenkins Server, and Setup Jenkins&lt;/h2&gt;
&lt;h3&gt;Step 1: Connect to the Jenkins Server&lt;/h3&gt;
&lt;p&gt;To connect to the Jenkins server, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the public IP address of the Jenkins server
AWS_PUBLIC_IP=$(aws ec2 describe-instances \
  --instance-ids $AWS_INSTANCE \
  --query &amp;#39;Reservations[0].Instances[0].PublicIpAddress&amp;#39; \
  --output text)

# Connect to the Jenkins server
ssh -i aws-key-pair.pem ec2-user@$AWS_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_PUBLIC_IP&lt;/code&gt; is a variable that holds the public IP address of the Jenkins server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ssh -i aws-key-pair.pem ec2-user@$AWS_PUBLIC_IP&lt;/code&gt; Connect to the Jenkins server.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Setup Jenkins&lt;/h3&gt;
&lt;p&gt;To setup Jenkins, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the initial admin password
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sudo cat /var/lib/jenkins/secrets/initialAdminPassword&lt;/code&gt; Get the initial admin password.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Configuring Jenkins&lt;/h3&gt;
&lt;p&gt;To configure Jenkins:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;code&gt;http://&amp;lt;public-ip-address&amp;gt;:8080/&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0031-install-jenkins-on-aws-ec2-instance/jenkins-1.png&quot; alt=&quot;jenkins-1&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Enter the initial admin password.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0031-install-jenkins-on-aws-ec2-instance/jenkins-2.png&quot; alt=&quot;jenkins-2&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Select the recommended plugins.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0031-install-jenkins-on-aws-ec2-instance/jenkins-3.png&quot; alt=&quot;jenkins-3&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Create the first admin user.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0031-install-jenkins-on-aws-ec2-instance/jenkins-4.png&quot; alt=&quot;jenkins-4&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Jenkins is ready.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0031-install-jenkins-on-aws-ec2-instance/jenkins-5.png&quot; alt=&quot;jenkins-5&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, you learned how to install Jenkins on an AWS EC2 instance.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/&quot;&gt;Jenkins Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/&quot;&gt;Jenkins User Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/installing/linux/&quot;&gt;Installing Jenkins on Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS Command Line Interface (CLI) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&quot;&gt;Amazon VPC User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html&quot;&gt;AWS Key Pairs and Amazon EC2 Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html&quot;&gt;Security Groups for your VPC - Amazon VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html&quot;&gt;User data and shell scripts for EC2 instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html&quot;&gt;Elastic IP addresses - Amazon EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html&quot;&gt;Connect to your Linux instance using SSH - Amazon EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/managing/plugins/&quot;&gt;Managing Jenkins Plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/pipeline/tour/getting-started/&quot;&gt;Getting started with Jenkins&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>Jenkins</category><category>EC2</category><category>DevOps</category><category>CI/CD</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0031-install-jenkins-on-aws-ec2-instance/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Run TypeScript Without Compiling</title><link>https://mkabumattar.com/blog/post/run-typescript-without-compiling/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/run-typescript-without-compiling/</guid><description>We can run TypeScript without compiling it to JavaScript. This is useful for debugging and testing. In this post, I will show you how to do it.</description><pubDate>Fri, 02 Dec 2022 18:43:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, I will show you how to run TypeScript without compiling it to JavaScript. This is useful for debugging and testing. In this post, I will show you how to do it.&lt;/p&gt;
&lt;h2&gt;Setup a TypeScript Project&lt;/h2&gt;
&lt;h3&gt;Step 1: Create a Directory&lt;/h3&gt;
&lt;p&gt;Create a directory for the project.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a directory
mkdir run-typescript-without-compiling

# Change directory
cd run-typescript-without-compiling
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Initialize a Node.js Project&lt;/h3&gt;
&lt;p&gt;Initialize a Node.js project.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Initialize a Node.js project
yarn init -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Install TypeScript and &lt;code&gt;@types/node&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Install TypeScript and &lt;code&gt;@types/node&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install TypeScript and @types/node
yarn add -D typescript @types/node
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Initialize a TypeScript Project&lt;/h3&gt;
&lt;p&gt;Initialize a TypeScript project.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Initialize a TypeScript project
yarn tsc --init
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 5: Create a TypeScript File&lt;/h3&gt;
&lt;p&gt;Create a TypeScript file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a src directory
mkdir src

# Create a TypeScript file
touch src/index.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 6: Example Code&lt;/h3&gt;
&lt;p&gt;Add the following code to the TypeScript file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const sum = (a: number, b: number): number =&amp;gt; a + b;
const subtract = (a: number, b: number): number =&amp;gt; a - b;
const multiply = (a: number, b: number): number =&amp;gt; a * b;
const divide = (a: number, b: number): number =&amp;gt; a / b;

console.log(sum(1, 2));
console.log(subtract(1, 2));
console.log(multiply(1, 2));
console.log(divide(1, 2));
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 7: Run the TypeScript File&lt;/h3&gt;
&lt;p&gt;Now, we will install &lt;code&gt;ts-node&lt;/code&gt; and run the TypeScript file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install ts-node
yarn add -D ts-node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following code to the &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  ...
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;playground&amp;quot;: &amp;quot;ts-node src/index.ts&amp;quot;,
    &amp;quot;playground:watch&amp;quot;: &amp;quot;nodemon -e ts -w . -x esr src/index.ts&amp;quot;,
    &amp;quot;build&amp;quot;: &amp;quot;tsc&amp;quot;,
    &amp;quot;build:watch&amp;quot;: &amp;quot;tsc -w&amp;quot;,
    &amp;quot;build:debug&amp;quot;: &amp;quot;tsc --sourceMap&amp;quot;,
    &amp;quot;build:debug:watch&amp;quot;: &amp;quot;tsc -w --sourceMap&amp;quot;,
    &amp;quot;start&amp;quot;: &amp;quot;node dist/index.js&amp;quot;,
    &amp;quot;start:watch&amp;quot;: &amp;quot;nodemon -e js -w dist -x esr dist/index.js&amp;quot;
  },
  ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;Notice type=&quot;note&quot;&gt;
  `nodemon` is a utility that will monitor for any changes in your source and
  automatically restart your server. You can install it using `yarn global add
  nodemon` or `npm install -g nodemon`.
&lt;/Notice&gt;&lt;p&gt;Run the TypeScript file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run the TypeScript file
yarn playground

# Output
3
-1
2
0.5
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I demonstrated how to run TypeScript in this article without converting it to JavaScript. For testing and troubleshooting, this is helpful. I demonstrate how to accomplish that in this post.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/&quot;&gt;TypeScript Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/ts-node&quot;&gt;ts-node on npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/TypeStrong/ts-node&quot;&gt;ts-node GitHub Repository (TypeStrong/ts-node)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/nodemon&quot;&gt;nodemon on npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodemon.io/&quot;&gt;nodemon Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/docs/&quot;&gt;Node.js Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yarnpkg.com/&quot;&gt;Yarn Package Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/tsconfig&quot;&gt;TypeScript &lt;code&gt;tsconfig.json&lt;/code&gt; Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/cli/v7/configuring-npm/package-json&quot;&gt;npm &lt;code&gt;package.json&lt;/code&gt; Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@types/node&quot;&gt;&lt;code&gt;@types/node&lt;/code&gt; package on npm&lt;/a&gt; (for Node.js type definitions)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/play&quot;&gt;TypeScript Playground&lt;/a&gt; (for quick experiments)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>TypeScript</category><category>Node.js</category><category>JavaScript</category><category>Development Tools</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0030-run-typescript-without-compiling/hero.jpg" length="0" type="image/jpeg"/></item><item><title>React With Redux Toolkit</title><link>https://mkabumattar.com/blog/post/react-with-redux-toolkit/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/react-with-redux-toolkit/</guid><description>In this post, we will learn how to use Redux Toolkit to manage the state of our React application.</description><pubDate>Fri, 02 Dec 2022 11:43:00 GMT</pubDate><content:encoded>&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;This post assumes that you have a basic understanding of React and Redux. and it will be better if you have some experience with React Hooks like &lt;code&gt;useReducer&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Nowadays, we have a lot of state management libraries for React, such as Redux, MobX, and Recoil. In this post, we will learn how to use Redux Toolkit to manage the state of our React application.&lt;/p&gt;
&lt;h3&gt;What is Redux?&lt;/h3&gt;
&lt;p&gt;Redux is a predictable state container for JavaScript apps. It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.&lt;/p&gt;
&lt;h3&gt;What is Redux Toolkit?&lt;/h3&gt;
&lt;p&gt;Redux Toolkit is the official, opinionated, batteries-included toolset for efficient Redux development. It is intended to be the standard way to write Redux logic.&lt;/p&gt;
&lt;p&gt;It was originally created to help address three common concerns about Redux:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configuring a Redux store is too complicated.&lt;/li&gt;
&lt;li&gt;I have to add a lot of packages to get Redux to do anything useful.&lt;/li&gt;
&lt;li&gt;Redux requires too much boilerplate code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Why Redux Toolkit?&lt;/h3&gt;
&lt;p&gt;Redux Toolkit is a package that contains a set of tools to help you write Redux logic more easily. It is not a Redux replacement, but it is an alternative to writing Redux logic by hand.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;h3&gt;Step 1: Initialize a React project using vite&lt;/h3&gt;
&lt;p&gt;First, we need to initialize a React project using vite.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# using npm
npm init vite react-with-redux-toolkit

# using yarn
yarn create vite react-with-redux-toolkit

# using pnpm
pnpm create vite react-with-redux-toolkit

# using npx
npx create-vite react-with-redux-toolkit
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# select the react
? Select a framework: react
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# select the javascript
? Select a variant: javascript
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;Notice type=&quot;note&quot;&gt;
  You can use `npm`, `yarn`, `pnpm`, or `npx` to initialize a React project
  using vite.
&lt;/Notice&gt;&lt;Notice type=&quot;note&quot;&gt;
  You can use `typescript` instead of `javascript` to initialize a React project
  using vite.
&lt;/Notice&gt;&lt;h3&gt;Step 2: Go to the project directory&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cd react-with-redux-toolkit
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Install Basic Dependencies&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# using npm
npm install

# using yarn
yarn install

# using pnpm
pnpm install
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Install Redux Toolkit&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# using npm
npm install @reduxjs/toolkit react-redux

# using yarn
yarn add @reduxjs/toolkit react-redux

# using pnpm
pnpm add @reduxjs/toolkit react-redux
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;h3&gt;Step 1: Remove the unnecessary files&lt;/h3&gt;
&lt;p&gt;We will remove the unnecessary files, or we can say that we will clean up &lt;code&gt;src&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;rm -rf src/*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rm&lt;/code&gt; - remove files or directories&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-rf&lt;/code&gt; - remove directories and their contents recursively&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Create the Basic Structure&lt;/h3&gt;
&lt;h4&gt;Step 2.1: Create the Folders and Files&lt;/h4&gt;
&lt;p&gt;We will create the basic structure of our project.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# create the components directory
mkdir src/components

# create the store directory
mkdir src/app

# create the App.jsx file
touch src/App.jsx

# create the main.jsx file
touch src/main.jsx
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 2.2: Create the &lt;code&gt;App.jsx&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;We will create the &lt;code&gt;App.jsx&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const App = () =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;React With Redux Toolkit - Part 1&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 2.3: Create the &lt;code&gt;main.jsx&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;We will create the &lt;code&gt;main.jsx&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import App from &amp;#39;./App&amp;#39;;
import React, {StrictMode} from &amp;#39;react&amp;#39;;
import ReactDOM from &amp;#39;react-dom/client&amp;#39;;

ReactDOM.createRoot(document.getElementById(&amp;#39;root&amp;#39;)).render(
  &amp;lt;StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/StrictMode&amp;gt;,
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Create the Store&lt;/h3&gt;
&lt;h4&gt;Step 3.1: Create the &lt;code&gt;store.js&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;We will create the &lt;code&gt;store.js&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import {configureStore} from &amp;#39;@reduxjs/toolkit&amp;#39;;

const store = configureStore({
  reducer: {},
});

export default store;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we have imported the &lt;code&gt;configureStore&lt;/code&gt; function from &lt;code&gt;@reduxjs/toolkit&lt;/code&gt; and we have created the store using the &lt;code&gt;configureStore&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import { configureStore } from &amp;#39;@reduxjs/toolkit&amp;#39;&lt;/code&gt; - import the configureStore function&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const store = configureStore({ reducer: {} })&lt;/code&gt; - create the store using the configureStore function&lt;/li&gt;
&lt;li&gt;&lt;code&gt;export default store&lt;/code&gt; - export the store&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;Notice type=&quot;note&quot;&gt;We will add the reducer later.&lt;/Notice&gt;&lt;/p&gt;
&lt;p&gt;After that we will do some changes to the main.jsx file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import App from &amp;#39;./App&amp;#39;;
import store from &amp;#39;./app/store&amp;#39;;
import React, {StrictMode} from &amp;#39;react&amp;#39;;
import ReactDOM from &amp;#39;react-dom/client&amp;#39;;
import {Provider} from &amp;#39;react-redux&amp;#39;;

ReactDOM.createRoot(document.getElementById(&amp;#39;root&amp;#39;)).render(
  &amp;lt;StrictMode&amp;gt;
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/Provider&amp;gt;
  &amp;lt;/StrictMode&amp;gt;,
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&amp;#39;ll notice that we have wrapped the App component with the &lt;code&gt;Provider&lt;/code&gt; component after importing it from the &lt;code&gt;react-redux&lt;/code&gt; library. Additionally, the store from &lt;code&gt;./app/store&lt;/code&gt; was imported. To the &lt;code&gt;Provider&lt;/code&gt; component, we have passed the &lt;code&gt;store&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import { Provider } from &amp;#39;react-redux&amp;#39;&lt;/code&gt; - import the Provider component&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import store from &amp;#39;./app/store&amp;#39;&lt;/code&gt; - import the store&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Provider store={store}&amp;gt;&lt;/code&gt; - pass the store to the Provider component&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Create the &lt;code&gt;counterSlice.js&lt;/code&gt; file&lt;/h3&gt;
&lt;p&gt;We will create the &lt;code&gt;counterSlice.js&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import {createSlice} from &amp;#39;@reduxjs/toolkit&amp;#39;;

const initialState = {
  count: 0,
};

const counterSlice = createSlice({
  name: &amp;#39;counter&amp;#39;,
  initialState,
  reducers: {
    increment: (state) =&amp;gt; {
      state.count += 1;
    },
    decrement: (state) =&amp;gt; {
      state.count -= 1;
    },
    reset: (state) =&amp;gt; {
      state.count = 0;
    },
    incrementByAmount: (state, action) =&amp;gt; {
      state.count += action.payload;
    },
  },
});

export const {increment, decrement, reset, incrementByAmount} =
  counterSlice.actions;

export default counterSlice.reducer;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;createSlice&lt;/code&gt; function is used to create a slice of the store. We have passed the name of the slice as &lt;code&gt;counter&lt;/code&gt;. We have passed the initial state of the slice as &lt;code&gt;initialState&lt;/code&gt;. We have passed the reducers as an object. We have passed the &lt;code&gt;increment&lt;/code&gt;, &lt;code&gt;decrement&lt;/code&gt;, &lt;code&gt;reset&lt;/code&gt;, and &lt;code&gt;incrementByAmount&lt;/code&gt; reducers. We have exported the &lt;code&gt;increment&lt;/code&gt;, &lt;code&gt;decrement&lt;/code&gt;, and &lt;code&gt;incrementByAmount&lt;/code&gt; actions. We have exported the reducer.&lt;/p&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import { createSlice } from &amp;#39;@reduxjs/toolkit&amp;#39;&lt;/code&gt; - import the createSlice function&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const initialState = { count: 0 }&lt;/code&gt; - define the initial state of the slice&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const counterSlice = createSlice({ name: &amp;#39;counter&amp;#39;, initialState, reducers: { increment: (state) =&amp;gt; { state.count += 1 }, decrement: (state) =&amp;gt; { state.count -= 1 }, reset: (state) =&amp;gt; { state.count = 0 }, incrementByAmount: (state, action) =&amp;gt; { state.count += action.payload }, } })&lt;/code&gt; - create the slice of the store&lt;/li&gt;
&lt;li&gt;&lt;code&gt;export const { increment, decrement, reset, incrementByAmount } = counterSlice.actions&lt;/code&gt; - export the actions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;export default counterSlice.reducer&lt;/code&gt; - export the reducer&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Add the &lt;code&gt;counterSlice&lt;/code&gt; reducer to the store&lt;/h3&gt;
&lt;p&gt;We will add the &lt;code&gt;counterSlice&lt;/code&gt; reducer to the store.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import counterReducer from &amp;#39;../components/Counter/counterSlice&amp;#39;;
import {configureStore} from &amp;#39;@reduxjs/toolkit&amp;#39;;

const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

export default store;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now after adding the &lt;code&gt;counterSlice&lt;/code&gt; reducer to the store, it will be available in the entire application.&lt;/p&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import counterReducer from &amp;#39;../components/Counter/counterSlice&amp;#39;&lt;/code&gt; - import the counterSlice reducer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reducer: { counter: counterReducer }&lt;/code&gt; - add the counterSlice reducer to the store&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 6: Add the Counter Component to the App Component&lt;/h3&gt;
&lt;p&gt;We will add the Counter Component to the App Component.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import {increment, decrement, reset, incrementByAmount} from &amp;#39;./counterSlice&amp;#39;;
import React from &amp;#39;react&amp;#39;;
import {useSelector, useDispatch} from &amp;#39;react-redux&amp;#39;;

const Counter = () =&amp;gt; {
  const count = useSelector((state) =&amp;gt; state.counter.count);
  const dispatch = useDispatch();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count: {count}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(increment())}&amp;gt;Increment&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(decrement())}&amp;gt;Decrement&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(reset())}&amp;gt;Reset&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(incrementByAmount(5))}&amp;gt;
        Increment By 5
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Counter;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we have imported the &lt;code&gt;useSelector&lt;/code&gt; hook from &lt;code&gt;react-redux&lt;/code&gt;. We have imported the &lt;code&gt;useDispatch&lt;/code&gt; hook from &lt;code&gt;react-redux&lt;/code&gt;. We have imported the &lt;code&gt;increment&lt;/code&gt;, &lt;code&gt;decrement&lt;/code&gt;, &lt;code&gt;reset&lt;/code&gt;, and &lt;code&gt;incrementByAmount&lt;/code&gt; actions from &lt;code&gt;./counterSlice&lt;/code&gt;. We have used the &lt;code&gt;useSelector&lt;/code&gt; hook to get the count from the store. We have used the &lt;code&gt;useDispatch&lt;/code&gt; hook to dispatch the actions. We have used the &lt;code&gt;increment&lt;/code&gt;, &lt;code&gt;decrement&lt;/code&gt;, &lt;code&gt;reset&lt;/code&gt;, and &lt;code&gt;incrementByAmount&lt;/code&gt; actions to dispatch the actions.&lt;/p&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import { useSelector, useDispatch } from &amp;#39;react-redux&amp;#39;&lt;/code&gt; - import the useSelector hook and the useDispatch hook&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import { increment, decrement, incrementByAmount } from &amp;#39;./counterSlice&amp;#39;&lt;/code&gt; - import the actions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const count = useSelector((state) =&amp;gt; state.counter.count)&lt;/code&gt; - get the count from the store&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const dispatch = useDispatch()&lt;/code&gt; - get the dispatch function&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onClick={() =&amp;gt; dispatch(increment())}&lt;/code&gt; - dispatch the increment action&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onClick={() =&amp;gt; dispatch(decrement())}&lt;/code&gt; - dispatch the decrement action&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onClick={() =&amp;gt; dispatch(reset())}&lt;/code&gt; - dispatch the reset action&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onClick={() =&amp;gt; dispatch(incrementByAmount(5))}&lt;/code&gt; - dispatch the incrementByAmount action&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 7: Add the Counter Component to the App Component&lt;/h3&gt;
&lt;p&gt;We will add the Counter Component to the App Component.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import Counter from &amp;#39;./components/Counter/Counter&amp;#39;;
import React from &amp;#39;react&amp;#39;;

const App = () =&amp;gt; (
  &amp;lt;div&amp;gt;
    &amp;lt;Counter /&amp;gt;
  &amp;lt;/div&amp;gt;
);

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we have imported the Counter Component. We have added the Counter Component to the App Component.&lt;/p&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import Counter from &amp;#39;./components/Counter/Counter&amp;#39;&lt;/code&gt; - import the Counter Component&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Counter /&amp;gt;&lt;/code&gt; - add the Counter Component to the App Component&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 8: Run the application&lt;/h3&gt;
&lt;p&gt;We will run the application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0029-react-with-redux-toolkit/redux-toolkit-counter.png&quot; alt=&quot;Redux Toolkit Counter&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you can see, we have a counter. We can increment the counter. We can decrement the counter. We can increment the counter by 5.&lt;/p&gt;
&lt;h3&gt;Step 9: Access &lt;code&gt;count&lt;/code&gt; value in other components&lt;/h3&gt;
&lt;p&gt;We will access the &lt;code&gt;count&lt;/code&gt; value in other components, for example, in the &lt;code&gt;Header&lt;/code&gt; component.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#39;react&amp;#39;;
import {useSelector} from &amp;#39;react-redux&amp;#39;;

const Header = () =&amp;gt; {
  const count = useSelector((state) =&amp;gt; state.counter.count);

  return (
    &amp;lt;header&amp;gt;
      &amp;lt;h1&amp;gt;Redux Toolkit Counter&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;Count: {count}&amp;lt;/p&amp;gt;
    &amp;lt;/header&amp;gt;
  );
};

export default Header;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we have imported the &lt;code&gt;useSelector&lt;/code&gt; hook from &lt;code&gt;react-redux&lt;/code&gt;. We have used the &lt;code&gt;useSelector&lt;/code&gt; hook to get the &lt;code&gt;count&lt;/code&gt; value from the store. We have added the &lt;code&gt;count&lt;/code&gt; value to the &lt;code&gt;Header&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import { useSelector } from &amp;#39;react-redux&amp;#39;&lt;/code&gt; - import the useSelector hook&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const count = useSelector((state) =&amp;gt; state.counter.count)&lt;/code&gt; - get the count from the store&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;p&amp;gt;Count: {count}&amp;lt;/p&amp;gt;&lt;/code&gt; - add the count to the Header component&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 10: Add the Header Component to the App Component&lt;/h3&gt;
&lt;p&gt;We will add the Header Component to the App Component.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import Counter from &amp;#39;./components/Counter/Counter&amp;#39;;
import Header from &amp;#39;./components/Header/Header&amp;#39;;
import React from &amp;#39;react&amp;#39;;

const App = () =&amp;gt; (
  &amp;lt;div&amp;gt;
    &amp;lt;Header /&amp;gt;
    &amp;lt;Counter /&amp;gt;
  &amp;lt;/div&amp;gt;
);

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we have imported the Header Component. We have added the Header Component to the App Component.&lt;/p&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import Header from &amp;#39;./components/Header/Header&amp;#39;&lt;/code&gt; - import the Header Component&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Header /&amp;gt;&lt;/code&gt; - add the Header Component to the App Component&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 11: Run the application&lt;/h3&gt;
&lt;p&gt;We will run the application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0029-react-with-redux-toolkit/redux-toolkit-counter-with-header.png&quot; alt=&quot;Redux Toolkit Counter with Header&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you can see, we have a counter. We can increment the counter. We can decrement the counter. We can increment the counter by 5. We have a header with the count value.&lt;/p&gt;
&lt;h2&gt;Source Code&lt;/h2&gt;
&lt;p&gt;You can find the source code for this tutorial on &lt;a href=&quot;https://github.com/MKAbuMattar/react-with-redux-toolkit&quot;&gt;GitHub&lt;/a&gt;. You can clone the repository and run the application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Clone the repository
git clone https://github.com/MKAbuMattar/react-with-redux-toolkit.git

# Go inside the directory
cd react-with-redux-toolkit

# Install dependencies
yarn install

# Run the application
yarn dev
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we learned how to establish a Redux store using the Redux Toolkit. A Redux slice can now be made, as we have learned. We now know how to take an action. We now know how to build reducers. We now know how to build a Redux store. The Redux store may now be added to the App Component, as we learned how to do. We now know how to add the Counter Component to the App Component. Accessing the &lt;code&gt;count&lt;/code&gt; value in other components is something we now know how to do. We have learned how to add the Header Component to the App Component.&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redux-toolkit.js.org/&quot;&gt;Redux Toolkit Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redux-toolkit.js.org/tutorials/quick-start&quot;&gt;Redux Toolkit Quick Start Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redux.js.org/&quot;&gt;Redux Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/&quot;&gt;React Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-redux.js.org/&quot;&gt;React Redux Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redux-toolkit.js.org/api/configureStore&quot;&gt;Redux Toolkit &lt;code&gt;configureStore&lt;/code&gt; API Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redux-toolkit.js.org/api/createSlice&quot;&gt;Redux Toolkit &lt;code&gt;createSlice&lt;/code&gt; API Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-redux.js.org/api/hooks&quot;&gt;Using Redux with React Hooks (&lt;code&gt;useSelector&lt;/code&gt;, &lt;code&gt;useDispatch&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/reduxjs/redux-devtools&quot;&gt;Redux DevTools Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redux.js.org/understanding/thinking-in-redux/three-principles&quot;&gt;Redux Core Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/context.html&quot;&gt;React Context (Alternative for simple state management)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/MKAbuMattar/react-with-redux-toolkit&quot;&gt;GitHub Repository for this tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>ReactJS</category><category>Redux</category><category>State Management</category><category>Frontend Development</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0029-react-with-redux-toolkit/hero.jpg" length="0" type="image/jpeg"/></item><item><title>What is DevOps?</title><link>https://mkabumattar.com/blog/post/what-is-devops/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/what-is-devops/</guid><description>DevOps is a set of practices that combines software development (Dev) and information technology operations (Ops). It aims to shorten the systems development life cycle and provide continuous delivery with high software quality.</description><pubDate>Fri, 18 Nov 2022 19:43:00 GMT</pubDate><content:encoded>&lt;h2&gt;What is DevOps, and why is it important?&lt;/h2&gt;
&lt;p&gt;The name &amp;quot;DevOps&amp;quot; is a combination of the terms &amp;quot;development&amp;quot; and &amp;quot;operations,&amp;quot; although it refers to a far broader range of principles and procedures than those two terms alone or together. Security, teamwork, data analytics, and many more concepts are all part of DevOps.&lt;/p&gt;
&lt;p&gt;DevOps refers to methods for accelerating the procedures by which an idea such as a new software feature, a request for an improvement, or a bug fix goes from development to deployment in a production environment where it may be useful to users. These methods call for frequent communication between development teams and operations teams, as well as an attitude of empathy for one another. Additionally required are scalability and flexible provisioning. Those that require the most power benefit from DevOps because of self-service and automation.&lt;/p&gt;
&lt;p&gt;What connection exist between containers and DevOps?&lt;/p&gt;
&lt;p&gt;DevOps expedites the process of taking an idea from conception to deployment. DevOps is fundamentally based on standardizing environments for the duration of an app&amp;#39;s lifecycle and automating repetitive administrative duties. Containers can provide uniform environments, but managing them requires a platform with built-in automation and support for any infrastructure.&lt;/p&gt;
&lt;h2&gt;What is the culture of DevOps?&lt;/h2&gt;
&lt;p&gt;DevOps depends on a collaborative environment that supports open source ideals and open, agile working practices.&lt;/p&gt;
&lt;p&gt;It is possible to create a DevOps culture by modeling it after the culture of open-source software projects. In open-source communities, collaboration usually takes the form of open information exchange. Implementing cultural changes such as increasing openness in decision-making, removing the fear of failure from the experimental process, or putting in place a reward system that fosters trust and cooperation can all be helpful. For the purpose of assisting with these sorts of projects, several businesses investigate consulting services for digital transformation.&lt;/p&gt;
&lt;p&gt;Your development and operations teams may contribute to fostering an open culture if the appropriate leadership and incentive programs are in place. But when this culture permeates the whole company, DevOps becomes the most successful. DevOps is for everyone, even if the word alludes to development and operations.&lt;/p&gt;
&lt;h2&gt;What is the DevOps process?&lt;/h2&gt;
&lt;p&gt;Modern application development demands different procedures than earlier methods did. Agile methods are popular in software development teams. DevOps is not an afterthought for these teams. In fact, the Agile Manifesto&amp;#39;s first of 12 principles is &amp;quot;Customer delight through early and continuous product delivery.&amp;quot; Because of this, DevOps teams place a high value on continuous integration and continuous deployment (CI/CD).&lt;/p&gt;
&lt;p&gt;However, simply altering your development and operational procedures is insufficient. If you want to truly improve the way you provide software, you must use systems thinking. Accordingly, DevOps will bring about changes in both the teams that provide end-user support and the business units that seek development work. The secret lies in an ongoing feedback loop between the firm and its customers.&lt;/p&gt;
&lt;p&gt;The way you do the task itself won&amp;#39;t need to alter; your method will. The type of employment you undertake will inevitably alter as well. With DevOps, you may develop new forms of software that are more suited to this continuous delivery cadence rather than merely speeding up the production of the same old monolithic software.&lt;/p&gt;
&lt;p&gt;Because of this, DevOps teams frequently use a microservices architecture while creating their software and use APIs to connect the services. Teams produce work more quickly when they concentrate on developing smaller chunks of functionality, therefore you must pay attention to how services and APIs are maintained and have a plan for integrating everything, such as agile integration. Even though these sorts of changes might be difficult to implement, the correct technology can help you get going right away. You can speed up your operations using automation, and eventually move your DevOps workloads to the cloud. According to an IDC report, 85% of IT executives believe automation is essential to their DevOps approach. This is so that an infrastructure can endure the continuous code changes brought on by DevOps.&lt;/p&gt;
&lt;h2&gt;What are the DevOps platform and tools?&lt;/h2&gt;
&lt;p&gt;The success of DevOps depends on choosing tools that complement your processes. Your operations must employ extremely flexible platforms and handle their infrastructure the same way that development teams treat their code if they are to stay up with the quick development cycles. Manual deployments are cumbersome and prone to mistakes. Automation may make platform deployment and provisioning simpler. These manually operated jobs are managed by Site Reliability Engineering (SRE) utilizing software and automation. The objectives of a DevOps team can be further supported by an SRE strategy.&lt;/p&gt;
&lt;h2&gt;Through continuous deployment, how can DevOps aid in scaling?&lt;/h2&gt;
&lt;p&gt;A continuous integration and continuous deployment pipeline (CI/CD) is a key result of applying DevOps. You can release apps to consumers often and check the quality of your software with little to no human involvement by using CI/CD. In order to rapidly discover and fix issues and defects, CI/CD adds continuing automation and continuous monitoring throughout the lifespan of apps, from the integration and testing phases through delivery and deployment. The development and operations teams collaborate in an agile manner to support these connected processes, which are collectively referred to as a &amp;quot;CI/CD pipeline.&amp;quot;&lt;/p&gt;
&lt;h2&gt;What is the DevOps lifecycle?&lt;/h2&gt;
&lt;p&gt;The DevOps lifecycle is a set of procedures that are used to develop, test, and deploy software. The DevOps lifecycle is a set of procedures that are used to develop, test, and deploy software. The DevOps lifecycle is a set of procedures that are used to develop, test, and deploy software. The DevOps lifecycle is a set of procedures that are used to develop, test, and deploy software.&lt;/p&gt;
&lt;h2&gt;What is the DevOps security?&lt;/h2&gt;
&lt;p&gt;DevOps isn&amp;#39;t only about development and operations teams, as we just said. Organizations must think about how security fits into the software life cycle in order to fully benefit from a DevOps strategy. This calls for considering core security from the beginning of the planning process. Additionally, it entails automating a few security elements to prevent a delay in the DevOps workflow. You may achieve your DevOps security objectives by using the appropriate technologies for integration security. Effective DevOps security, however, need much more than just new technologies; it relies on the cultural shifts brought about by DevOps to incorporate the work of security teams as quickly as possible. By bridging the gap between development and operations, DevOps expedites processes, yet the efficiency gained may be compromised.&lt;/p&gt;
&lt;p&gt;Previously, security was the exclusive responsibility of a small team that was added during the development process. Security is now an integrated, shared responsibility inside a collaborative DevOps architecture.&lt;/p&gt;
&lt;h2&gt;What is the DevOps methodology?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Continuous Integration (CI)&lt;/strong&gt;: The process of integrating code changes into a shared repository several times a day. This is done to ensure that the code is always in a deployable state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Deployment (CD)&lt;/strong&gt;: The process of automatically deploying code changes to a production environment several times a day. This is done to ensure that the code is always in a deployable state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Monitoring (CM)&lt;/strong&gt;: The process of monitoring the production environment to ensure that the code is always in a deployable state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Feedback (CF)&lt;/strong&gt;: The process of gathering feedback from users to ensure that the code is always in a deployable state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Learning (CL)&lt;/strong&gt;: The process of learning from the feedback to ensure that the code is always in a deployable state.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.atlassian.com/devops&quot;&gt;What is DevOps? - Atlassian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/devops/what-is-devops/&quot;&gt;What is DevOps? - Amazon Web Services (AWS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/overview/what-is-devops/&quot;&gt;What is DevOps? - Microsoft Azure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://itrevolution.com/devops-handbook/&quot;&gt;The DevOps Handbook&lt;/a&gt; by Gene Kim, Jez Humble, Patrick Debois, and John Willis&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.redhat.com/en/topics/devops/what-is-ci-cd&quot;&gt;What is CI/CD? - Red Hat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.redhat.com/en/topics/devops/what-is-devsecops&quot;&gt;What is DevSecOps? - Red Hat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://agilemanifesto.org/&quot;&gt;Agile Manifesto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sre.google/sre-book/table-of-contents/&quot;&gt;Site Reliability Engineering (SRE) - Google&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinfowler.com/articles/microservices.html&quot;&gt;Microservices - Martin Fowler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinfowler.com/articles/continuousIntegration.html&quot;&gt;Continuous Integration - Martin Fowler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/what-is-a-ci-cd&quot;&gt;What is a CI/CD pipeline?&lt;/a&gt; (Internal link, assuming this is a valid path)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/solutions/devops/&quot;&gt;DevOps and Containers - Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://itrevolution.com/the-phoenix-project/&quot;&gt;The Phoenix Project: A Novel About IT, DevOps, and Helping Your Business Win&lt;/a&gt; by Gene Kim, Kevin Behr, and George Spafford&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://puppet.com/resources/report/state-of-devops-report&quot;&gt;State of DevOps Report - Puppet&lt;/a&gt; (Annual report with insights)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>DevOps</category><category>Software Development</category><category>IT Operations</category><category>Agile</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0028-what-is-devops/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Connect A EBS Volume To An Windows EC2 Instance Using Powershell/GUI</title><link>https://mkabumattar.com/blog/post/how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/</guid><description>In this post, we will learn how to connect a EBS volume to an Windows EC2 instance using Powershell/GUI</description><pubDate>Tue, 15 Nov 2022 18:06:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, we will learn how to connect a EBS volume to an Windows EC2 instance using Powershell/GUI and also how to mount the EBS volume to the EC2 instance.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI installed and configured&lt;/li&gt;
&lt;li&gt;IAM user with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonVPCFullAccess&lt;/li&gt;
&lt;li&gt;AmazonEC2FullAccess&lt;/li&gt;
&lt;li&gt;AmazonElasticBlockStoreFullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create an VPC&lt;/h2&gt;
&lt;h3&gt;Step 1: Create VPC&lt;/h3&gt;
&lt;p&gt;To create a VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a VPC
AWS_VPC=$(aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --query &amp;#39;Vpc.VpcId&amp;#39; \
  --output text)

# Add a name tag to the VPC
aws ec2 create-tags \
  --resources $AWS_VPC \
  --tags Key=Name,Value=aws-vpc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-vpc&lt;/code&gt; - Create a VPC&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr-block&lt;/code&gt; - The IPv4 network range for the VPC, in CIDR notation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Modify your custom VPC and enable DNS hostname support, and DNS support&lt;/h3&gt;
&lt;p&gt;To modify your custom VPC and enable DNS hostname support, and DNS support, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable DNS hostnames
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-hostnames &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;

# Enable DNS support
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-support &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 modify-vpc-attribute&lt;/code&gt; - Modifies the specified attribute of the specified VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--enable-dns-hostnames&lt;/code&gt; - Indicates whether the instances launched in the VPC get DNS hostnames.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--enable-dns-support&lt;/code&gt; - Indicates whether DNS resolution is supported for the VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Create a Public Subnet&lt;/h3&gt;
&lt;p&gt;To create a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a public subnet
AWS_PUBLIC_SUBNET=$(aws ec2 create-subnet \
  --vpc-id $AWS_VPC \
  --cidr-block 10.0.1.0/24 \
  --query &amp;#39;Subnet.SubnetId&amp;#39; \
  --output text)

# Add a name tag to the public subnet
aws ec2 create-tags \
  --resources $AWS_PUBLIC_SUBNET \
  --tags Key=Name,Value=aws-public-subnet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-subnet&lt;/code&gt; - Creates a subnet in an existing VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr-block&lt;/code&gt; - The IPv4 network range for the subnet, in CIDR notation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Enable Auto-assign Public IP on the subnet&lt;/h3&gt;
&lt;p&gt;To enable auto-assign public IP on the subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable auto-assign public IP on the subnet
aws ec2 modify-subnet-attribute \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --map-public-ip-on-launch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 modify-subnet-attribute&lt;/code&gt; - Modifies a subnet attribute.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; - The ID of the subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--map-public-ip-on-launch&lt;/code&gt; - Specify true to indicate that network interfaces created in the specified subnet should be assigned a public IPv4 address.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Create an Internet Gateway&lt;/h3&gt;
&lt;p&gt;To create an Internet Gateway, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an Internet Gateway
AWS_INTERNET_GATEWAY=$(aws ec2 create-internet-gateway \
  --query &amp;#39;InternetGateway.InternetGatewayId&amp;#39; \
  --output text)

# Add a name tag to the Internet Gateway
aws ec2 create-tags \
  --resources $AWS_INTERNET_GATEWAY \
  --tags Key=Name,Value=aws-internet-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-internet-gateway&lt;/code&gt; - Creates an Internet gateway for use with a VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 6: Attach the Internet Gateway to the VPC&lt;/h3&gt;
&lt;p&gt;To attach the Internet Gateway to the VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the Internet Gateway to the VPC
aws ec2 attach-internet-gateway \
  --internet-gateway-id $AWS_INTERNET_GATEWAY \
  --vpc-id $AWS_VPC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 attach-internet-gateway&lt;/code&gt; - Attaches an Internet gateway to a VPC, enabling connectivity between the Internet and the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--internet-gateway-id&lt;/code&gt; - The ID of the Internet gateway.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 7: Create a Route Table&lt;/h3&gt;
&lt;p&gt;To create a route table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a route table
AWS_ROUTE_TABLE=$(aws ec2 create-route-table \
  --vpc-id $AWS_VPC \
  --query &amp;#39;RouteTable.RouteTableId&amp;#39; \
  --output text)

# Add a name tag to the route table
aws ec2 create-tags \
  --resources $AWS_ROUTE_TABLE \
  --tags Key=Name,Value=aws-route-table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-route-table&lt;/code&gt; - Creates a route table for the specified VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 8: Create a custom route table association&lt;/h3&gt;
&lt;p&gt;To create a custom route table association, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a custom route table association
aws ec2 associate-route-table \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --route-table-id $AWS_ROUTE_TABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 associate-route-table&lt;/code&gt; - Associates a subnet with a route table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; - The ID of the subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--route-table-id&lt;/code&gt; - The ID of the route table.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 9: Associate the subnet with route table, making it a public subnet&lt;/h3&gt;
&lt;p&gt;To associate the subnet with route table, making it a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the subnet with route table, making it a public subnet
aws ec2 create-route \
  --route-table-id $AWS_ROUTE_TABLE \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id $AWS_INTERNET_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-route&lt;/code&gt; - Creates a route in a route table within a VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--route-table-id&lt;/code&gt; - The ID of the route table for the route.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--destination-cidr-block&lt;/code&gt; - The IPv4 CIDR address block used for the destination match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--gateway-id&lt;/code&gt; - The ID of an Internet gateway or virtual private gateway attached to your VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 10: Create a Security Group&lt;/h3&gt;
&lt;p&gt;To create a security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a security group
AWS_SECURITY_GROUP=$(aws ec2 create-security-group \
  --group-name aws-security-group \
  --description &amp;quot;AWS Security Group&amp;quot; \
  --vpc-id $AWS_VPC \
  --query &amp;#39;GroupId&amp;#39; \
  --output text)

# Add a name tag to the security group
aws ec2 create-tags \
  --resources $AWS_SECURITY_GROUP \
  --tags Key=Name,Value=aws-security-group
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-security-group&lt;/code&gt; - Creates a security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--group-name&lt;/code&gt; - The name of the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--description&lt;/code&gt; - A description for the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 11: Add a rule to the security group&lt;/h3&gt;
&lt;p&gt;To add a rule to the security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add a rule to the security group

# Allow RDP &amp;gt;&amp;gt; remote desktop protocol
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 3389 \
  --cidr 0.0.0.0/0 \
  --output text

# Add HTTP rule
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 80 \
  --cidr 0.0.0.0/0 \
  --output text

# Add HTTPS rule
aws ec2 authorize-security-group-ingress \
  --group-id $AWS_SECURITY_GROUP \
  --protocol tcp \
  --port 443 \
  --cidr 0.0.0.0/0 \
  --output text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 authorize-security-group-ingress&lt;/code&gt; - Adds one or more ingress rules to a security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--group-id&lt;/code&gt; - The ID of the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--protocol&lt;/code&gt; - The IP protocol name or number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--port&lt;/code&gt; - The port number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr&lt;/code&gt; - The IPv4 CIDR range.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create a Windows Server 2022 EC2 Instance&lt;/h2&gt;
&lt;h3&gt;Step 1: Get the latest AMI ID&lt;/h3&gt;
&lt;p&gt;To get the latest AMI ID, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the latest AMI ID
AWS_AMI=$(aws ec2 describe-images \
  --owners &amp;#39;amazon&amp;#39; \
  --filters &amp;#39;Name=name,Values=amzn2-ami-hvm-2.0.*&amp;#39; \
  &amp;#39;Name=state,Values=available&amp;#39; \
  --query &amp;#39;sort_by(Images, &amp;amp;CreationDate)[-1].[ImageId]&amp;#39; \
  --output &amp;#39;text&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 describe-images&lt;/code&gt; - Describes one or more of the images (AMIs, AKIs, and ARIs) available to you. Images available to you include public images, private images that you own, and private images owned by other AWS accounts but for which you have explicit launch permissions.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--owners&lt;/code&gt; - Filters the images by the owner. Specify an AWS account ID, &lt;code&gt;self&lt;/code&gt; (owner is the sender of the request), or an AWS owner alias (valid values are &lt;code&gt;amazon&lt;/code&gt;, &lt;code&gt;aws-marketplace&lt;/code&gt;, &lt;code&gt;microsoft&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--filters&lt;/code&gt; - One or more filters. Use a filter to return a more specific list of results.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Create a Key Pair&lt;/h3&gt;
&lt;p&gt;To create a key pair, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a key pair
aws ec2 create-key-pair \
  --key-name aws-key-pair \
  --query &amp;#39;KeyMaterial&amp;#39; \
  --output text &amp;gt; aws-key-pair.pem

# Change the permissions of the key pair
chmod 400 aws-key-pair.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-key-pair&lt;/code&gt; - Creates a 2048-bit RSA key pair with the specified name. Amazon EC2 stores the public key and displays the private key for you to save to a file. The private key is returned as an unencrypted PEM encoded PKCS#8 private key. If a key with the specified name already exists, Amazon EC2 returns an error.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-name&lt;/code&gt; - The name for your key pair.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;
  The private key, which is returned as an unencrypted PEM encoded PKCS#8
  private key, is only returned if you have access to the key pair. You must
  provide the corresponding key pair file when you launch an instance.
&lt;/Notice&gt;&lt;Notice type=&quot;note&quot;&gt;
  The key pair you will decrypted using AWS EC2 console, to get the password.
&lt;/Notice&gt;&lt;h3&gt;Step 3: Create an EC2 Instance&lt;/h3&gt;
&lt;p&gt;To create an EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an EC2 instance
AWS_INSTANCE=$(aws ec2 run-instances \
  --image-id $AWS_AMI \
  --instance-type t2.micro \
  --key-name aws-key-pair \
  --monitoring &amp;quot;Enabled=false&amp;quot; \
  --security-group-ids $AWS_SECURITY_GROUP \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --query &amp;#39;Instances[0].InstanceId&amp;#39; \
  --output text)

# Add a name tag to the EC2 instance
aws ec2 create-tags \
  --resources $AWS_INSTANCE \
  --tags Key=Name,Value=aws-instance-windows
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 run-instances&lt;/code&gt; - Launches the specified number of instances using an AMI for which you have permissions.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--image-id&lt;/code&gt; - The ID of the AMI.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-type&lt;/code&gt; - The instance type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-name&lt;/code&gt; - The name of the key pair.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--monitoring&lt;/code&gt; - Enables detailed monitoring (disabled by default).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--security-group-ids&lt;/code&gt; - The IDs of the security groups.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; - The ID of the subnet in which to launch the instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Wait for the EC2 Instance to be running&lt;/h3&gt;
&lt;p&gt;To wait for the EC2 instance to be running, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Wait for the EC2 instance to be running
aws ec2 wait instance-running \
  --instance-ids $AWS_INSTANCE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 wait instance-running&lt;/code&gt; - Wait until an instance is running.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-ids&lt;/code&gt; - The IDs of the instances.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Get the public IP address of the EC2 Instance&lt;/h3&gt;
&lt;p&gt;To get the public IP address of the EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the public IP address of the EC2 instance
AWS_PUBLIC_IP=$(aws ec2 describe-instances \
  --instance-ids $AWS_INSTANCE \
  --query &amp;#39;Reservations[0].Instances[0].PublicIpAddress&amp;#39; \
  --output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 describe-instances&lt;/code&gt; - Describes one or more of your instances.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-ids&lt;/code&gt; - The IDs of the instances.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create an EBS Volume&lt;/h2&gt;
&lt;h3&gt;Step 1: Create an EBS Volume&lt;/h3&gt;
&lt;p&gt;To create an EBS volume, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the availability zone for the EC2 instance
AWS_AVAILABILITY_ZONE=$(aws ec2 describe-instances \
  --instance-ids $AWS_INSTANCE \
  --query &amp;#39;Reservations[0].Instances[0].Placement.AvailabilityZone&amp;#39; \
  --output text)

# Create an EBS volume
AWS_VOLUME=$(aws ec2 create-volume \
  --availability-zone $AWS_AVAILABILITY_ZONE \
  --size 10 \
  --volume-type gp2 \
  --query &amp;#39;VolumeId&amp;#39; \
  --output text)

# Add a name tag to the EBS volume
aws ec2 create-tags \
  --resources $AWS_VOLUME \
  --tags Key=Name,Value=aws-volume
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 describe-instances&lt;/code&gt; - Describes one or more of your instances.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-ids&lt;/code&gt; - The IDs of the instances.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-volume&lt;/code&gt; - Creates an EBS volume that can be attached to an instance in the same Availability Zone.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--availability-zone&lt;/code&gt; - The Availability Zone in which to create the volume.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--size&lt;/code&gt; - The size of the volume, in GiBs.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--volume-type&lt;/code&gt; - The volume type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;
  Availability zone for the EC2 instance and EBS volume must be the same.
  Otherwise, you will get the following error: `InvalidParameterValue: The
  requested Availability Zone is currently constrained and only m3.medium or
  m3.large instances can be launched.`
&lt;/Notice&gt;&lt;h3&gt;Step 2: Wait for the EBS Volume to be available&lt;/h3&gt;
&lt;p&gt;To wait for the EBS volume to be available, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Wait for the EBS volume to be available
aws ec2 wait volume-available \
  --volume-ids $AWS_VOLUME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 wait volume-available&lt;/code&gt; - Wait until a volume is in the available state.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--volume-ids&lt;/code&gt; - The IDs of the volumes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Attach the EBS Volume to the EC2 Instance&lt;/h2&gt;
&lt;h3&gt;Step 1: Attach the EBS Volume to the Windows Server EC2 Instance&lt;/h3&gt;
&lt;p&gt;To attach the EBS volume to the Windows Server EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the EBS volume to the Windows Server EC2 instance
aws ec2 attach-volume \
  --device xvdf \
  --instance-id $AWS_INSTANCE \
  --volume-id $AWS_VOLUME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 attach-volume&lt;/code&gt; - Attaches an EBS volume to a running or stopped instance and exposes it to the instance with the specified device name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--device&lt;/code&gt; - The device name (for example, /dev/sdh or xvdh).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-id&lt;/code&gt; - The ID of the instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--volume-id&lt;/code&gt; - The ID of the EBS volume.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Wait for the EBS Volume to be in-use&lt;/h3&gt;
&lt;p&gt;To wait for the EBS volume to be in-use, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Wait for the EBS volume to be in-use
aws ec2 wait volume-in-use \
  --volume-ids $AWS_VOLUME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 wait volume-in-use&lt;/code&gt; - Wait until a volume is in the in-use state.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--volume-ids&lt;/code&gt; - The IDs of the volumes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Connect to the Windows Server EC2 Instance&lt;/h2&gt;
&lt;h3&gt;Step 1: Connect to the Windows Server EC2 Instance using RDP (Remote Desktop Protocol) in Linux&lt;/h3&gt;
&lt;p&gt;If you are using Linux, you can connect to the Windows Server EC2 instance using RDP (Remote Desktop Protocol) in Linux. To do so, you need to install the &lt;code&gt;remmina&lt;/code&gt; package. To install the &lt;code&gt;remmina&lt;/code&gt; package, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install the remmina package

# Arch Linux
sudo pacman -S remmina

# Debian/Ubuntu
sudo apt install remmina -y

# CentOS/RHEL
sudo yum install remmina -y

# Fedora
sudo dnf install remmina -y

# OpenSUSE
sudo zypper install remmina -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pacman&lt;/code&gt; - Arch Linux package manager.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apt&lt;/code&gt; - Debian/Ubuntu package manager.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yum&lt;/code&gt; - CentOS/RHEL package manager.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dnf&lt;/code&gt; - Fedora package manager.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zypper&lt;/code&gt; - OpenSUSE package manager.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 1.1: Create a new RDP connection&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Click on the &lt;code&gt;+&lt;/code&gt; button to add a new connection.&lt;/li&gt;
&lt;li&gt;Enter the following details:&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Name&lt;/code&gt; - Enter a name for the connection.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Protocol&lt;/code&gt; - Select &lt;code&gt;RDP&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Server&lt;/code&gt; - Enter the public IP address of the Windows Server EC2 instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Username&lt;/code&gt; - Enter the username of the Windows Server EC2 instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Password&lt;/code&gt; - Enter the password of the Windows Server EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;Save&lt;/code&gt; button.&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;&lt;p&gt;To get the password of the Windows Server EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the password of the Windows Server EC2 instance
EC2_INSTANCE_PASSWORD=$(aws ec2 get-password-data \
  --instance-id $AWS_INSTANCE \
  --priv-launch-key aws-key-pair.pem \
  --query &amp;#39;PasswordData&amp;#39; \
  --output text)

# Desplay the password of the Windows Server EC2 instance
echo $EC2_INSTANCE_PASSWORD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 get-password-data&lt;/code&gt; - Retrieves the encrypted administrator password for the instances running Windows.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-id&lt;/code&gt; - The ID of the instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--priv-launch-key&lt;/code&gt; - The private key that is required to decrypt the password data.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0027-how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/remmina.png&quot; alt=&quot;remmina&quot;&gt;&lt;/p&gt;
&lt;/Notice&gt;&lt;h4&gt;Step 1.2: Connect to the Windows Server EC2 Instance&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Click on the &lt;code&gt;Connect&lt;/code&gt; button to connect to the Windows Server EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0027-how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/connect-to-the-windows-server-ec2-instance.png&quot; alt=&quot;Connect to the Windows Server EC2 Instance&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Step 2: Connect to the Windows Server EC2 Instance using RDP (Remote Desktop Protocol) in Windows&lt;/h3&gt;
&lt;p&gt;If you are using Windows, you can connect to the Windows Server EC2 instance using RDP (Remote Desktop Protocol) in Windows. To do so, you need to install the &lt;code&gt;Microsoft Remote Desktop&lt;/code&gt; app. To install the &lt;code&gt;Microsoft Remote Desktop&lt;/code&gt; app, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install the Microsoft Remote Desktop app
winget install Microsoft.RemoteDesktop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;winget&lt;/code&gt; - Windows package manager.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 2.1: Create a new RDP connection&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Click on the &lt;code&gt;+&lt;/code&gt; button to add a new connection.&lt;/li&gt;
&lt;li&gt;Enter the following details:&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Name&lt;/code&gt; - Enter a name for the connection.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Computer&lt;/code&gt; - Enter the public IP address of the Windows Server EC2 instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Username&lt;/code&gt; - Enter the username of the Windows Server EC2 instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Password&lt;/code&gt; - Enter the password of the Windows Server EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;&lt;p&gt;To get the password of the Windows Server EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the password of the Windows Server EC2 instance
EC2_INSTANCE_PASSWORD=$(aws ec2 get-password-data \
  --instance-id $AWS_INSTANCE \
  --priv-launch-key aws-key-pair.pem \
  --query &amp;#39;PasswordData&amp;#39; \
  --output text)

# Desplay the password of the Windows Server EC2 instance
echo $EC2_INSTANCE_PASSWORD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 get-password-data&lt;/code&gt; - Retrieves the encrypted administrator password for the instances running Windows.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-id&lt;/code&gt; - The ID of the instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--priv-launch-key&lt;/code&gt; - The private key that is required to decrypt the password data.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0027-how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/microsoft-remote-desktop.png&quot; alt=&quot;Microsoft Remote Desktop&quot;&gt;&lt;/p&gt;
&lt;/Notice&gt;&lt;h4&gt;Step 2.2: Connect to the Windows Server EC2 Instance&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Click on the &lt;code&gt;Connect&lt;/code&gt; button to connect to the Windows Server EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0027-how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/connect-to-the-windows-server-ec2-instance-windows.png&quot; alt=&quot;Connect to the Windows Server EC2 Instance&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Connect to the EBS Volume&lt;/h2&gt;
&lt;h3&gt;Connect to the EBS Volume using PowerShell&lt;/h3&gt;
&lt;h4&gt;Step 1: Connect to the EBS Volume using PowerShell&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Open the &lt;code&gt;PowerShell&lt;/code&gt; app.&lt;/li&gt;
&lt;li&gt;Run the following command to connect to the EBS volume:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# Connect to diskpart
diskpart

# List the disks
list disk

# Select the disk
select disk 1

# initialize the disk
convert gpt

# Create a new partition
create partition primary

# List the partitions
list partition

# Select the partition
select partition 2

# Assign a drive letter
assign letter=D

# Format the partition
format fs=ntfs quick

# Exit diskpart
exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;diskpart&lt;/code&gt; - DiskPart is a command-line tool that you can use to manage disks and volumes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list disk&lt;/code&gt; - Lists all disks on the computer.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select disk&lt;/code&gt; - Selects a disk for use.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;convert gpt&lt;/code&gt; - Converts a disk to the GPT partition style.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create partition primary&lt;/code&gt; - Creates a primary partition on the selected disk.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list partition&lt;/code&gt; - Lists all partitions on the selected disk.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select partition&lt;/code&gt; - Selects a partition for use.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assign letter&lt;/code&gt; - Assigns a drive letter to the selected partition.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;format fs=ntfs quick&lt;/code&gt; - Formats the selected partition.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exit&lt;/code&gt; - Exits DiskPart.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0027-how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/connect-to-the-ebs-volume-using-powershell.png&quot; alt=&quot;Connect to the EBS Volume using PowerShell&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Step 2: Check the EBS Volume&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Run the following command to check the EBS volume:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# List the disks
Get-Partition | Get-Volume
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Get-Partition&lt;/code&gt; - Gets the partitions on a disk.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Get-Volume&lt;/code&gt; - Gets the volumes on a disk.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0027-how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/check-the-ebs-volume.png&quot; alt=&quot;Check the EBS Volume&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Connect to the EBS Volume using Disk Management&lt;/h3&gt;
&lt;h4&gt;Step 1: Connect to the EBS Volume using Disk Management&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Open the Sersh bar by pressing the &lt;code&gt;Windows&lt;/code&gt; key + &lt;code&gt;S&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;diskmgmt.msc&lt;/code&gt; and press &lt;code&gt;Enter&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Right-click on the &lt;code&gt;Disk 1&lt;/code&gt; and click on the &lt;code&gt;Online&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;Right-click on the &lt;code&gt;Disk 1&lt;/code&gt; and click on the &lt;code&gt;Initialize Disk&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;Right-click on the &lt;code&gt;Unallocated&lt;/code&gt; space and click on the &lt;code&gt;New Simple Volume&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;Next&lt;/code&gt; button.&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;Next&lt;/code&gt; button.&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;Next&lt;/code&gt; button.&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;Finish&lt;/code&gt; button.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0027-how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/connect-to-the-ebs-volume-using-disk-management.png&quot; alt=&quot;Connect to the EBS Volume using Disk Management&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Step 2: Check the EBS Volume using Disk Management&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Right-click on the &lt;code&gt;Disk 1&lt;/code&gt; and click on the &lt;code&gt;Properties&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;Volumes&lt;/code&gt; tab.&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;D:&lt;/code&gt; drive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0027-how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/check-the-ebs-volume-using-disk-management.png&quot; alt=&quot;Check the EBS Volume&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to connect a EBS volume to an Windows EC2 instance using PowerShell GUI.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Windows Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volumes.html&quot;&gt;Amazon EBS volumes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-attaching-volume.html&quot;&gt;Attach an Amazon EBS volume to an instance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ebs-using-volumes.html&quot;&gt;Make an Amazon EBS volume available for use on Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS Command Line Interface (CLI) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/index.html&quot;&gt;AWS CLI Command Reference - ec2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&quot;&gt;Amazon VPC User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/connecting_to_windows_instance.html&quot;&gt;Connect to your Windows instance using RDP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/diskpart&quot;&gt;DiskPart command-line options (Microsoft Docs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows-server/storage/disk-management/initialize-new-disks&quot;&gt;Initialize new disks (Microsoft Docs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/storage/get-disk&quot;&gt;PowerShell Get-Disk cmdlet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/storage/initialize-disk&quot;&gt;PowerShell Initialize-Disk cmdlet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/storage/new-partition&quot;&gt;PowerShell New-Partition cmdlet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/storage/format-volume&quot;&gt;PowerShell Format-Volume cmdlet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>Windows Server</category><category>EC2</category><category>EBS</category><category>PowerShell</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0027-how-to-connect-a-ebs-volume-to-an-windows-ec2-instance-using-powershell-gui/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Connect A Two EC2 Instances Database and Files Transfer Using AWS CLI</title><link>https://mkabumattar.com/blog/post/how-to-connect-a-two-ec2-instances-database-and-files-transfer-using-aws-cli/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-connect-a-two-ec2-instances-database-and-files-transfer-using-aws-cli/</guid><description>In this post, I will show you how to connect a two EC2 instances database and files transfer using AWS CLI. I will use AWS CLI to create a VPC, EC2 instances, EBS, EFS, and security groups. I will use the EC2 instances to connect to the database and files transfer.</description><pubDate>Sun, 13 Nov 2022 18:06:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, I will show you how to connect a two EC2 instances database and files transfer using AWS CLI. I will use AWS CLI to create a VPC, EC2 instances, EBS, EFS, and security groups. I will use the EC2 instances to connect to the database and files transfer.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI installed and configured&lt;/li&gt;
&lt;li&gt;IAM user with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonVPCFullAccess&lt;/li&gt;
&lt;li&gt;AmazonEC2FullAccess&lt;/li&gt;
&lt;li&gt;AmazonElasticBlockStoreFullAccess&lt;/li&gt;
&lt;li&gt;AmazonElasticFileSystemFullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create VPC&lt;/h2&gt;
&lt;h3&gt;Step 1: Create VPC&lt;/h3&gt;
&lt;p&gt;To create a VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a VPC
AWS_VPC=$(aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --query &amp;#39;Vpc.VpcId&amp;#39; \
  --output text)

# Add a name tag to the VPC
aws ec2 create-tags \
  --resources $AWS_VPC \
  --tags Key=Name,Value=aws-vpc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-vpc&lt;/code&gt; - Create a VPC&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr-block&lt;/code&gt; - The IPv4 network range for the VPC, in CIDR notation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Modify your custom VPC and enable DNS hostname support, and DNS support&lt;/h3&gt;
&lt;p&gt;To modify your custom VPC and enable DNS hostname support, and DNS support, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable DNS hostnames
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-hostnames &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;

# Enable DNS support
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-support &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 modify-vpc-attribute&lt;/code&gt; - Modifies the specified attribute of the specified VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--enable-dns-hostnames&lt;/code&gt; - Indicates whether the instances launched in the VPC get DNS hostnames.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--enable-dns-support&lt;/code&gt; - Indicates whether DNS resolution is supported for the VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Create a Public Subnet&lt;/h3&gt;
&lt;p&gt;To create a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a public subnet
AWS_PUBLIC_SUBNET=$(aws ec2 create-subnet \
  --vpc-id $AWS_VPC \
  --cidr-block 10.0.1.0/24 \
  --query &amp;#39;Subnet.SubnetId&amp;#39; \
  --output text)

# Add a name tag to the public subnet
aws ec2 create-tags \
  --resources $AWS_PUBLIC_SUBNET \
  --tags Key=Name,Value=aws-public-subnet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-subnet&lt;/code&gt; - Creates a subnet in an existing VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr-block&lt;/code&gt; - The IPv4 network range for the subnet, in CIDR notation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Enable Auto-assign Public IP on the subnet&lt;/h3&gt;
&lt;p&gt;To enable auto-assign public IP on the subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable auto-assign public IP on the subnet
aws ec2 modify-subnet-attribute \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --map-public-ip-on-launch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 modify-subnet-attribute&lt;/code&gt; - Modifies a subnet attribute.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; - The ID of the subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--map-public-ip-on-launch&lt;/code&gt; - Specify true to indicate that network interfaces created in the specified subnet should be assigned a public IPv4 address.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Create an Internet Gateway&lt;/h3&gt;
&lt;p&gt;To create an Internet Gateway, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an Internet Gateway
AWS_INTERNET_GATEWAY=$(aws ec2 create-internet-gateway \
  --query &amp;#39;InternetGateway.InternetGatewayId&amp;#39; \
  --output text)

# Add a name tag to the Internet Gateway
aws ec2 create-tags \
  --resources $AWS_INTERNET_GATEWAY \
  --tags Key=Name,Value=aws-internet-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-internet-gateway&lt;/code&gt; - Creates an Internet gateway for use with a VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 6: Attach the Internet Gateway to the VPC&lt;/h3&gt;
&lt;p&gt;To attach the Internet Gateway to the VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the Internet Gateway to the VPC
aws ec2 attach-internet-gateway \
  --internet-gateway-id $AWS_INTERNET_GATEWAY \
  --vpc-id $AWS_VPC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 attach-internet-gateway&lt;/code&gt; - Attaches an Internet gateway to a VPC, enabling connectivity between the Internet and the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--internet-gateway-id&lt;/code&gt; - The ID of the Internet gateway.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 7: Create a Route Table&lt;/h3&gt;
&lt;p&gt;To create a route table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a route table
AWS_ROUTE_TABLE=$(aws ec2 create-route-table \
  --vpc-id $AWS_VPC \
  --query &amp;#39;RouteTable.RouteTableId&amp;#39; \
  --output text)

# Add a name tag to the route table
aws ec2 create-tags \
  --resources $AWS_ROUTE_TABLE \
  --tags Key=Name,Value=aws-route-table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-route-table&lt;/code&gt; - Creates a route table for the specified VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 8: Create a custom route table association&lt;/h3&gt;
&lt;p&gt;To create a custom route table association, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a custom route table association
aws ec2 associate-route-table \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --route-table-id $AWS_ROUTE_TABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 associate-route-table&lt;/code&gt; - Associates a subnet with a route table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; - The ID of the subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--route-table-id&lt;/code&gt; - The ID of the route table.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 9: Associate the subnet with route table, making it a public subnet&lt;/h3&gt;
&lt;p&gt;To associate the subnet with route table, making it a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the subnet with route table, making it a public subnet
aws ec2 create-route \
  --route-table-id $AWS_ROUTE_TABLE \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id $AWS_INTERNET_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-route&lt;/code&gt; - Creates a route in a route table within a VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--route-table-id&lt;/code&gt; - The ID of the route table for the route.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--destination-cidr-block&lt;/code&gt; - The IPv4 CIDR address block used for the destination match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--gateway-id&lt;/code&gt; - The ID of an Internet gateway or virtual private gateway attached to your VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 10: Create a Security Group&lt;/h3&gt;
&lt;p&gt;To create a security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a security group
AWS_SECURITY_GROUP=$(aws ec2 create-security-group \
  --group-name aws-security-group \
  --description &amp;quot;AWS Security Group&amp;quot; \
  --vpc-id $AWS_VPC \
  --query &amp;#39;GroupId&amp;#39; \
  --output text)

# Add a name tag to the security group
aws ec2 create-tags \
  --resources $AWS_SECURITY_GROUP \
  --tags Key=Name,Value=aws-security-group
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-security-group&lt;/code&gt; - Creates a security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--group-name&lt;/code&gt; - The name of the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--description&lt;/code&gt; - A description for the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 11: Add a rule to the security group&lt;/h3&gt;
&lt;p&gt;To add a rule to the security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add a rule to the security group

# Add SSH rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 22 \
--cidr 0.0.0.0/0 \
--output text

# Add HTTP rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 80 \
--cidr 0.0.0.0/0 \
--output text

# Add HTTPS rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 443 \
--cidr 0.0.0.0/0 \
--output text

# Add NFS rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 2049 \
--cidr 0.0.0.0/0 \
--output text

# Add mysql/arura rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 3306 \
--cidr 0.0.0.0/0 \
--output text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 authorize-security-group-ingress&lt;/code&gt; - Adds one or more ingress rules to a security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--group-id&lt;/code&gt; - The ID of the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--protocol&lt;/code&gt; - The IP protocol name or number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--port&lt;/code&gt; - The port number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr&lt;/code&gt; - The IPv4 CIDR range.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create a Two EC2 Instances&lt;/h2&gt;
&lt;h3&gt;Step 1: Get the latest AMI ID&lt;/h3&gt;
&lt;p&gt;To get the latest AMI ID, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the latest AMI ID
AWS_AMI=$(aws ec2 describe-images \
  --owners &amp;#39;amazon&amp;#39; \
  --filters &amp;#39;Name=name,Values=amzn2-ami-hvm-2.0.*&amp;#39; \
  &amp;#39;Name=state,Values=available&amp;#39; \
  --query &amp;#39;sort_by(Images, &amp;amp;CreationDate)[-1].[ImageId]&amp;#39; \
  --output &amp;#39;text&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 describe-images&lt;/code&gt; - Describes one or more of the images (AMIs, AKIs, and ARIs) available to you.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--owners&lt;/code&gt; - Filters the images by the owner.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--filters&lt;/code&gt; - The filters to apply to the images.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Create a Key Pair&lt;/h3&gt;
&lt;p&gt;To create a key pair, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a key pair
aws ec2 create-key-pair \
--key-name aws-key-pair \
--query &amp;#39;KeyMaterial&amp;#39; \
--output text &amp;gt; aws-key-pair.pem

# Change the permission of the key pair
chmod 400 aws-key-pair.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-key-pair&lt;/code&gt; - Creates a 2048-bit RSA key pair with the specified name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-name&lt;/code&gt; - The name for the key pair.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chmod 400 aws-key-pair.pem&lt;/code&gt; - Changes the permission of the key pair, making it read-only.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Create a User Data Script&lt;/h3&gt;
&lt;p&gt;To create a user data script, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a user data script
cat &amp;lt;&amp;lt;EOF &amp;gt; user-data.sh
#!/bin/bash

# Variables
ROOT_DB_PASSWORD=&amp;quot;121612&amp;quot;
DB_NAME=&amp;quot;DB&amp;quot;
DB_USER=&amp;quot;user&amp;quot;
DB_PASSWORD=&amp;quot;121612&amp;quot;

# update the system
sudo yum update -y

# install efs-utils
sudo yum install git rpm-build make -y

# clone the efs-utils repository
git clone https://github.com/aws/efs-utils

# change directory to efs-utils
cd efs-utils

# build the efs-utils
make rpm

# install the efs-utils
sudo yum install build/amazon-efs-utils*rpm -y

# install httpd
sudo yum install httpd -y

# start httpd
sudo systemctl start httpd

# enable httpd
sudo systemctl enable httpd

# At first, we will enable amazon-linux-extras so that we can specify the PHP version that we want to install.
sudo amazon-linux-extras enable php7.4 -y

# Install PHP
sudo yum install php php-{pear,cgi,common,curl,mbstring,gd,mysqlnd,gettext,bcmath,json,xml,fpm,intl,zip,imap} -y

# Install MariaDB
sudo yum install mariadb-server -y

# Start MariaDB
sudo systemctl start mariadb

# Enable MariaDB
sudo systemctl enable mariadb

# Restart Apache
sudo systemctl restart httpd

# We will now secure MariaDB.
sudo mysql_secure_installation &amp;lt;&amp;lt;EOF2

y
$ROOT_DB_PASSWORD
$ROOT_DB_PASSWORD
y
y
y
y
EOF2

# Create a database
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;CREATE DATABASE $DB_NAME;&amp;quot;

# Create a user
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;CREATE USER &amp;#39;$DB_USER&amp;#39;@&amp;#39;localhost&amp;#39; IDENTIFIED BY &amp;#39;$DB_PASSWORD&amp;#39;;&amp;quot;

# Grant privileges
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;GRANT ALL PRIVILEGES ON $DB_NAME.* TO &amp;#39;$DB_USER&amp;#39;@&amp;#39;localhost&amp;#39;;&amp;quot;

# Flush privileges
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;FLUSH PRIVILEGES;&amp;quot;

# Create PHP page

cat &amp;lt;&amp;lt;EOF3 &amp;gt; /var/www/html/index.php
&amp;lt;?php
\$servername = &amp;quot;localhost&amp;quot;;
\$username = &amp;quot;$DB_USER&amp;quot;;
\$password = &amp;quot;$DB_PASSWORD&amp;quot;;
\$dbname = &amp;quot;$DB_NAME&amp;quot;;

// Create connection
try {
    \$conn = new PDO(&amp;quot;mysql:host=\$servername;dbname=\$dbname&amp;quot;, \$username, \$password);
    // set the PDO error mode to exception
    \$conn-&amp;gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo &amp;quot;Connected successfully&amp;quot;;
} catch(PDOException \$e) {
    echo &amp;quot;Connection failed: &amp;quot; . \$e-&amp;gt;getMessage();
}
?&amp;gt;
EOF3

# Restart Apache
sudo systemctl restart httpd

EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The user data script performs the following tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Updates the system.&lt;/li&gt;
&lt;li&gt;Installs the EFS utilities.&lt;/li&gt;
&lt;li&gt;Installs Apache HTTP Server.&lt;/li&gt;
&lt;li&gt;Installs PHP.&lt;/li&gt;
&lt;li&gt;Installs MariaDB.&lt;/li&gt;
&lt;li&gt;Secures MariaDB.&lt;/li&gt;
&lt;li&gt;Creates a database.&lt;/li&gt;
&lt;li&gt;Creates a user.&lt;/li&gt;
&lt;li&gt;Grants privileges to the user.&lt;/li&gt;
&lt;li&gt;Creates a PHP page.&lt;/li&gt;
&lt;li&gt;Restarts Apache HTTP Server.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a user data script
cat &amp;lt;&amp;lt;EOF &amp;gt; user-data2.sh
#!/bin/bash

# Variables
ROOT_DB_PASSWORD=&amp;quot;121612&amp;quot;
DB_NAME=&amp;quot;DB&amp;quot;
DB_USER=&amp;quot;user&amp;quot;
DB_PASSWORD=&amp;quot;121612&amp;quot;

# update the system
sudo yum update -y

# install efs-utils
sudo yum install git rpm-build make -y

# clone the efs-utils repository
git clone https://github.com/aws/efs-utils

# change directory to efs-utils
cd efs-utils

# build the efs-utils
make rpm

# install the efs-utils
sudo yum install build/amazon-efs-utils*rpm -y

# install httpd
sudo yum install httpd -y

# start httpd
sudo systemctl start httpd

# enable httpd
sudo systemctl enable httpd

# At first, we will enable amazon-linux-extras so that we can specify the PHP version that we want to install.
sudo amazon-linux-extras enable php7.4 -y

# Install PHP
sudo yum install php php-{pear,cgi,common,curl,mbstring,gd,mysqlnd,gettext,bcmath,json,xml,fpm,intl,zip,imap} -y

# Install MariaDB
sudo yum install mariadb-server -y

# Start MariaDB
sudo systemctl start mariadb

# Enable MariaDB
sudo systemctl enable mariadb

# Restart Apache
sudo systemctl restart httpd

# We will now secure MariaDB.
sudo mysql_secure_installation &amp;lt;&amp;lt;EOF2

y
$ROOT_DB_PASSWORD
$ROOT_DB_PASSWORD
y
y
y
y
EOF2

EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The user data script performs the following tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Updates the system.&lt;/li&gt;
&lt;li&gt;Installs the EFS utilities.&lt;/li&gt;
&lt;li&gt;Installs Apache HTTP Server.&lt;/li&gt;
&lt;li&gt;Installs PHP.&lt;/li&gt;
&lt;li&gt;Installs MariaDB.&lt;/li&gt;
&lt;li&gt;Restarts Apache HTTP Server.&lt;/li&gt;
&lt;li&gt;Secures MariaDB.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Create a Two EC2 Instances&lt;/h3&gt;
&lt;p&gt;To create two EC2 instances, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create two EC2 instances
AWS_EC2_INSTANCE_1=$(aws ec2 run-instances \
--image-id $AWS_AMI \
--instance-type t2.micro \
--key-name aws-key-pair \
--monitoring &amp;quot;Enabled=false&amp;quot; \
--security-group-ids $AWS_SECURITY_GROUP \
--subnet-id $AWS_PUBLIC_SUBNET \
--user-data file://user-data.sh \
--query &amp;#39;Instances[0].InstanceId&amp;#39; \
--output text)

AWS_EC2_INSTANCE_2=$(aws ec2 run-instances \
--image-id $AWS_AMI \
--instance-type t2.micro \
--key-name aws-key-pair \
--monitoring &amp;quot;Enabled=false&amp;quot; \
--security-group-ids $AWS_SECURITY_GROUP \
--subnet-id $AWS_PUBLIC_SUBNET \
--user-data file://user-data2.sh \
--query &amp;#39;Instances[0].InstanceId&amp;#39; \
--output text)

# Add a tag to the instances
aws ec2 create-tags \
--resources $AWS_EC2_INSTANCE_1 \
--tags Key=Name,Value=ec2-instance-1

aws ec2 create-tags \
--resources $AWS_EC2_INSTANCE_2 \
--tags Key=Name,Value=ec2-instance-2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_EC2_INSTANCE_1&lt;/code&gt; and &lt;code&gt;AWS_EC2_INSTANCE_2&lt;/code&gt; are variables that store the instance IDs of the two EC2 instances.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;aws ec2 run-instances&lt;/code&gt; command creates two EC2 instances.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--image-id&lt;/code&gt; option specifies the AMI ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--instance-type&lt;/code&gt; option specifies the instance type.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--key-name&lt;/code&gt; option specifies the key pair name.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--monitoring&lt;/code&gt; option specifies whether detailed monitoring is enabled.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--security-group-ids&lt;/code&gt; option specifies the security group ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--subnet-id&lt;/code&gt; option specifies the subnet ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--user-data&lt;/code&gt; option specifies the user data script.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--query&lt;/code&gt; option specifies the query to retrieve the instance ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--output&lt;/code&gt; option specifies the output format.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;aws ec2 create-tags&lt;/code&gt; command adds a tag to the instances.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create an EBS Volume&lt;/h2&gt;
&lt;h3&gt;Step 1: Create an EBS Volume With Multiple&lt;/h3&gt;
&lt;p&gt;To create an EBS volume with all availability zones, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_AVAILABILITY_ZONE=$(aws ec2 describe-availability-zones \
--query &amp;#39;AvailabilityZones[*].ZoneName&amp;#39; \
--output text)

# Create an EBS volume with all availability zones
AWS_EBS_VOLUME=$(aws ec2 create-volume \
--availability-zone $AWS_AVAILABILITY_ZONE \
--size 1 \
--volume-type io1 \
--iops 100 \
--query &amp;#39;VolumeId&amp;#39; \
--output text)

# Add a tag to the EBS volume
aws ec2 create-tags \
--resources $AWS_EBS_VOLUME \
--tags Key=Name,Value=ebs-volume
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_AVAILABILITY_ZONE&lt;/code&gt; is a variable that stores the availability zone.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;aws ec2 describe-availability-zones&lt;/code&gt; command retrieves the availability zone.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--query&lt;/code&gt; option specifies the query to retrieve the availability zone.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--output&lt;/code&gt; option specifies the output format.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;aws ec2 create-volume&lt;/code&gt; command creates an EBS volume.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--availability-zone&lt;/code&gt; option specifies the availability zone.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--size&lt;/code&gt; option specifies the size of the volume, in GiB.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--volume-type&lt;/code&gt; option specifies the volume type.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--iops&lt;/code&gt; option specifies the number of I/O operations per second (IOPS) that the volume supports.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--query&lt;/code&gt; option specifies the query to retrieve the volume ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--output&lt;/code&gt; option specifies the output format.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;aws ec2 create-tags&lt;/code&gt; command adds a tag to the EBS volume.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Attach the EBS Volume to the First EC2 Instance&lt;/h3&gt;
&lt;p&gt;To attach the EBS volume to the first EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the EBS volume to the first EC2 instance
aws ec2 attach-volume \
--device /dev/sdf \
--instance-id $AWS_EC2_INSTANCE_1 \
--volume-id $AWS_EBS_VOLUME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;aws ec2 attach-volume&lt;/code&gt; command attaches the EBS volume to the first EC2 instance.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--device&lt;/code&gt; option specifies the device name.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--instance-id&lt;/code&gt; option specifies the instance ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--volume-id&lt;/code&gt; option specifies the volume ID.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Create a File System and Mount the EBS Volume&lt;/h3&gt;
&lt;p&gt;To create a file system and mount the EBS volume, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# connect to the first EC2 instance
ssh -i aws-key-pair.pem ec2-user@$AWS_EC2_INSTANCE_1_PUBLIC_IP

# create a file system
sudo mkfs -t ext4 /dev/xvdf

# create a directory
sudo mkdir /data

# mount the EBS volume
sudo mount /dev/xvdf /data

# add the EBS volume to the fstab file
sudo echo &amp;quot;/dev/xvdf /data ext4 defaults 0 0&amp;quot; &amp;gt;&amp;gt; /etc/fstab

# exit the first EC2 instance
exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ssh&lt;/code&gt; command connects to the first EC2 instance.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mkfs -t ext4 /dev/xvdf&lt;/code&gt; command creates a file system.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mkdir /data&lt;/code&gt; command creates a directory.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mount /dev/xvdf /data&lt;/code&gt; command mounts the EBS volume.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo echo &amp;quot;/dev/xvdf /data ext4 defaults 0 0&amp;quot; &amp;gt;&amp;gt; /etc/fstab&lt;/code&gt; command adds the EBS volume to the fstab file.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;exit&lt;/code&gt; command exits the first EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Attach the EBS Volume to the Second EC2 Instance&lt;/h3&gt;
&lt;p&gt;To attach the EBS volume to the second EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the EBS volume to the second EC2 instance
aws ec2 attach-volume \
--device /dev/sdf \
--instance-id $AWS_EC2_INSTANCE_2 \
--volume-id $AWS_EBS_VOLUME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;aws ec2 attach-volume&lt;/code&gt; command attaches the EBS volume to the second EC2 instance.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--device&lt;/code&gt; option specifies the device name.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--instance-id&lt;/code&gt; option specifies the instance ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--volume-id&lt;/code&gt; option specifies the volume ID.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Create a File System and Mount the EBS Volume&lt;/h3&gt;
&lt;p&gt;To create a file system and mount the EBS volume, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# connect to the second EC2 instance
ssh -i aws-key-pair.pem ec2-user@$AWS_EC2_INSTANCE_2_PUBLIC_IP

# create a file system
sudo mkfs -t ext4 /dev/xvdf

# create a directory
sudo mkdir /data

# mount the EBS volume
sudo mount /dev/xvdf /data

# add the EBS volume to the fstab file
sudo echo &amp;quot;/dev/xvdf /data ext4 defaults 0 0&amp;quot; &amp;gt;&amp;gt; /etc/fstab

# exit the second EC2 instance
exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ssh&lt;/code&gt; command connects to the second EC2 instance.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mkfs -t ext4 /dev/xvdf&lt;/code&gt; command creates a file system.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mkdir /data&lt;/code&gt; command creates a directory.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mount /dev/xvdf /data&lt;/code&gt; command mounts the EBS volume.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo echo &amp;quot;/dev/xvdf /data ext4 defaults 0 0&amp;quot; &amp;gt;&amp;gt; /etc/fstab&lt;/code&gt; command adds the EBS volume to the fstab file.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;exit&lt;/code&gt; command exits the second EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create an EFS File System&lt;/h2&gt;
&lt;h3&gt;Step 1: Create an EFS File System&lt;/h3&gt;
&lt;p&gt;To create an EFS file system, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an EFS file system
AWS_EFS_FILE_SYSTEM=$(aws efs create-file-system \
--performance-mode generalPurpose \
--throughput-mode bursting \
--query &amp;#39;FileSystemId&amp;#39; \
--output text)

# Add a tag to the EFS file system
aws efs create-tags \
--file-system-id $AWS_EFS_FILE_SYSTEM \
--tags Key=Name,Value=efs-file-system
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;aws efs create-file-system&lt;/code&gt; command creates an EFS file system.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--performance-mode&lt;/code&gt; option specifies the performance mode.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--throughput-mode&lt;/code&gt; option specifies the throughput mode.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--query&lt;/code&gt; option specifies the query to retrieve the file system ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--output&lt;/code&gt; option specifies the output format.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;aws efs create-tags&lt;/code&gt; command adds a tag to the EFS file system.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Create an EFS Mount Target&lt;/h3&gt;
&lt;p&gt;To create an EFS mount target, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an EFS mount target
AWS_EFS_MOUNT_TARGET=$(aws efs create-mount-target \
--file-system-id $AWS_EFS_FILE_SYSTEM \
--subnet-id $AWS_PUBLIC_SUBNET \
--security-groups $AWS_SECURITY_GROUP \
--query &amp;#39;MountTargetId&amp;#39; \
--output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;aws efs create-mount-target&lt;/code&gt; command creates an EFS mount target.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--file-system-id&lt;/code&gt; option specifies the file system ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--subnet-id&lt;/code&gt; option specifies the subnet ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--security-groups&lt;/code&gt; option specifies the security group ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--query&lt;/code&gt; option specifies the query to retrieve the mount target ID.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--output&lt;/code&gt; option specifies the output format.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Mount the EFS File System to Two EC2 Instances&lt;/h3&gt;
&lt;p&gt;To mount the EFS file system to two EC2 instances, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# connect to the first EC2 instance
ssh -i aws-key-pair.pem ec2-user@$AWS_EC2_INSTANCE_1_PUBLIC_IP

# mount the EFS file system
sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 $AWS_EFS_FILE_SYSTEM.efs.$AVAILABILITY_ZONE.amazonaws.com:/ /var/www/html

# add the EFS file system to the fstab file
sudo echo &amp;quot;$AWS_EFS_FILE_SYSTEM.efs.$AVAILABILITY_ZONE.amazonaws.com:/ /var/www/html nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0&amp;quot; &amp;gt;&amp;gt; /etc/fstab

# exit the first EC2 instance
exit

# connect to the second EC2 instance
ssh -i aws-key-pair.pem ec2-user@$AWS_EC2_INSTANCE_2_PUBLIC_IP

# mount the EFS file system
sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 $AWS_EFS_FILE_SYSTEM.efs.$AVAILABILITY_ZONE.amazonaws.com:/ /var/www/html

# add the EFS file system to the fstab file
sudo echo &amp;quot;$AWS_EFS_FILE_SYSTEM.efs.$AVAILABILITY_ZONE.amazonaws.com:/ /var/www/html nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0&amp;quot; &amp;gt;&amp;gt; /etc/fstab

# exit the second EC2 instance
exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ssh&lt;/code&gt; command connects to the first EC2 instance.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 $AWS_EFS_FILE_SYSTEM.efs.$AVAILABILITY_ZONE.amazonaws.com:/ /var/www/html&lt;/code&gt; command mounts the EFS file system.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo echo &amp;quot;$AWS_EFS_FILE_SYSTEM.efs.$AVAILABILITY_ZONE.amazonaws.com:/ /var/www/html nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0&amp;quot; &amp;gt;&amp;gt; /etc/fstab&lt;/code&gt; command adds the EFS file system to the fstab file.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;exit&lt;/code&gt; command exits the first EC2 instance.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ssh&lt;/code&gt; command connects to the second EC2 instance.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 $AWS_EFS_FILE_SYSTEM.efs.$AVAILABILITY_ZONE.amazonaws.com:/ /var/www/html&lt;/code&gt; command mounts the EFS file system.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo echo &amp;quot;$AWS_EFS_FILE_SYSTEM.efs.$AVAILABILITY_ZONE.amazonaws.com:/ /var/www/html nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0&amp;quot; &amp;gt;&amp;gt; /etc/fstab&lt;/code&gt; command adds the EFS file system to the fstab file.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;exit&lt;/code&gt; command exits the second EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create a Database Replication on EBS&lt;/h2&gt;
&lt;h3&gt;Step 1: Create a Database Replication on EBS&lt;/h3&gt;
&lt;p&gt;To create a database replication on EBS, run the following command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connect to the first EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Connect to the first EC2 instance
ssh -i aws-key-pair.pem ec2-user@$AWS_EC2_INSTANCE_1_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Create a database Replication&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Variables
ROOT_DB_PASSWORD=&amp;quot;121612&amp;quot;

# Create a database Replication
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;CREATE USER &amp;#39;replication&amp;#39;@&amp;#39;%&amp;#39; IDENTIFIED BY &amp;#39;121612&amp;#39;;&amp;quot;
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;GRANT REPLICATION SLAVE ON *.* TO &amp;#39;replication&amp;#39;@&amp;#39;%&amp;#39;;&amp;quot;
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;FLUSH PRIVILEGES;&amp;quot;
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;SHOW MASTER STATUS;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;CREATE USER &amp;#39;replication&amp;#39;@&amp;#39;%&amp;#39; IDENTIFIED BY &amp;#39;121612&amp;#39;;&amp;quot;&lt;/code&gt; command creates a database replication.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;GRANT REPLICATION SLAVE ON *.* TO &amp;#39;replication&amp;#39;@&amp;#39;%&amp;#39;;&amp;quot;&lt;/code&gt; command grants replication slave on all databases to the replication user.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;FLUSH PRIVILEGES;&amp;quot;&lt;/code&gt; command flushes the privileges.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;SHOW MASTER STATUS;&amp;quot;&lt;/code&gt; command shows the master status.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connect to the second EC2 instance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Connect to the second EC2 instance
ssh -i aws-key-pair.pem ec2-user@$AWS_EC2_INSTANCE_2_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Create a database Replication&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Variables
ROOT_DB_PASSWORD=&amp;quot;121612&amp;quot;
AWS_EC2_INSTANCE_1_PRIVATE_IP=&amp;#39;&amp;#39;

# Create a database Replication
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;CHANGE MASTER TO MASTER_HOST=&amp;#39;$AWS_EC2_INSTANCE_1_PRIVATE_IP&amp;#39;, MASTER_USER=&amp;#39;replication&amp;#39;, MASTER_PASSWORD=&amp;#39;password&amp;#39;, MASTER_LOG_FILE=&amp;#39;mysql-bin.000001&amp;#39;, MASTER_LOG_POS=0;&amp;quot;
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;START SLAVE;&amp;quot;
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;SHOW SLAVE STATUS\G;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;CHANGE MASTER TO MASTER_HOST=&amp;#39;$AWS_EC2_INSTANCE_1_PRIVATE_IP&amp;#39;, MASTER_USER=&amp;#39;replication&amp;#39;, MASTER_PASSWORD=&amp;#39;password&amp;#39;, MASTER_LOG_FILE=&amp;#39;mysql-bin.000001&amp;#39;, MASTER_LOG_POS=0;&amp;quot;&lt;/code&gt; command changes the master to the first EC2 instance.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;START SLAVE;&amp;quot;&lt;/code&gt; command starts the slave.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;SHOW SLAVE STATUS\G;&amp;quot;&lt;/code&gt; command shows the slave status.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Test the Replication&lt;/h2&gt;
&lt;h3&gt;Step 1: Test the Replication&lt;/h3&gt;
&lt;p&gt;To test the replication, run the following command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connect to the first EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Connect to the first EC2 instance
ssh -i aws-key-pair.pem ec2-user@$AWS_EC2_INSTANCE_1_PUBLIC_IP

# Variables
ROOT_DB_PASSWORD=&amp;quot;121612&amp;quot;

# Create a database MK LLC
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;CREATE DATABASE MKLLC;&amp;quot;

# Create a table users
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; CREATE TABLE users (id INT NOT NULL AUTO_INCREMENT, FIRST_NAME VARCHAR(255) NOT NULL, LAST_NAME VARCHAR(255) NOT NULL, PRIMARY KEY (id));&amp;quot;

# Insert a record to the table users
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; INSERT INTO users (FIRST_NAME, LAST_NAME) VALUES (&amp;#39;John&amp;#39;, &amp;#39;Doe&amp;#39;);&amp;quot;
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; INSERT INTO users (FIRST_NAME, LAST_NAME) VALUES (&amp;#39;Jane&amp;#39;, &amp;#39;Doe&amp;#39;);&amp;quot;
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; INSERT INTO users (FIRST_NAME, LAST_NAME) VALUES (&amp;#39;Jack&amp;#39;, &amp;#39;Doe&amp;#39;);&amp;quot;
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; INSERT INTO users (FIRST_NAME, LAST_NAME) VALUES (&amp;#39;Jill&amp;#39;, &amp;#39;Doe&amp;#39;);&amp;quot;
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; INSERT INTO users (FIRST_NAME, LAST_NAME) VALUES (&amp;#39;Joe&amp;#39;, &amp;#39;Doe&amp;#39;);&amp;quot;

# Select all records from the table users
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; SELECT * FROM users;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;CREATE DATABASE MKLLC;&amp;quot;&lt;/code&gt; command creates a database MK LLC.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; CREATE TABLE users (id INT NOT NULL AUTO_INCREMENT, FIRST_NAME VARCHAR(255) NOT NULL, LAST_NAME VARCHAR(255) NOT NULL, PRIMARY KEY (id));&amp;quot;&lt;/code&gt; command creates a table users.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; INSERT INTO users (FIRST_NAME, LAST_NAME) VALUES (&amp;#39;FIRST_NAME&amp;#39;, &amp;#39;FIRST_NAME&amp;#39;);&amp;quot;&lt;/code&gt; command inserts a record to the table users.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; SELECT * FROM users;&amp;quot;&lt;/code&gt; command selects all records from the table users.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connect to the second EC2 instance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Connect to the second EC2 instance
ssh -i aws-key-pair.pem ec2-user@$AWS_EC2_INSTANCE_2_PUBLIC_IP

# Variables
ROOT_DB_PASSWORD=&amp;quot;121612&amp;quot;

# Select all records from the table users
sudo mysql -u root -p$ROOT_DB_PASSWORD -e &amp;quot;USE MKLLC; SELECT * FROM users;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the replication is successful, the command returns the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;+----+------------+-----------+
| id | FIRST_NAME | LAST_NAME |
+----+------------+-----------+
|  1 | John       | Doe       |
|  2 | Jane       | Doe       |
|  3 | Jack       | Doe       |
|  4 | Jill       | Doe       |
|  5 | Joe        | Doe       |
+----+------------+-----------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command tests the replication.&lt;/p&gt;
&lt;h2&gt;Why is the Replication Important?&lt;/h2&gt;
&lt;p&gt;The replication is important because it provides the following benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It provides high availability.&lt;/li&gt;
&lt;li&gt;It provides disaster recovery.&lt;/li&gt;
&lt;li&gt;It provides data redundancy.&lt;/li&gt;
&lt;li&gt;It provides data security.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The replication is important.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, you learned how to create a database replication on EBS and EFS. You also learned why the replication is important.&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonEBS.html&quot;&gt;Amazon EBS User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/efs/latest/ug/whatisefs.html&quot;&gt;Amazon EFS User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&quot;&gt;Amazon VPC User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS Command Line Interface (CLI) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/index.html&quot;&gt;AWS CLI Command Reference - ec2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/efs/index.html&quot;&gt;AWS CLI Command Reference - efs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/replication.html&quot;&gt;MySQL Replication Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/efs/latest/ug/mounting-fs.html&quot;&gt;Mounting EFS file systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-attaching-volume.html&quot;&gt;Attaching an Amazon EBS volume to an instance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html&quot;&gt;User data and shell scripts for EC2 instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html&quot;&gt;Security groups for your VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html&quot;&gt;Tutorial: Installing a LAMP Web Server on Amazon Linux 2&lt;/a&gt; (Relevant for setting up MariaDB/PHP)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>EC2</category><category>EBS</category><category>EFS</category><category>Database</category><category>Networking</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0026-how-to-connect-a-two-ec2-instances-database-and-files-transfer-using-aws-cli/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Connect A Two EC2 Instances Data Transfer Using AWS CLI Without AWS EFS</title><link>https://mkabumattar.com/blog/post/how-to-connect-a-two-ec2-instances-data-transfer-using-aws-cli-without-aws-efs/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-connect-a-two-ec2-instances-data-transfer-using-aws-cli-without-aws-efs/</guid><description>In this post, I will show you how to connect a two EC2 instances data transfer using AWS CLI without AWS EFS.</description><pubDate>Fri, 11 Nov 2022 20:22:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, I will show you how to connect a two EC2 instances data transfer using AWS CLI without AWS EFS.&lt;/p&gt;
&lt;p&gt;We will use AWS S3 bucket to transfer data between two EC2 instances. We will create a AWS S3 bucket and upload a file to it. Then we will download the file from the AWS S3 bucket to the other EC2 instance.&lt;/p&gt;
&lt;p&gt;Why we will use AWS S3 bucket to transfer data between two EC2 instances? Because AWS S3 bucket is a highly available, durable, and scalable object storage service. It is designed to make web-scale computing easier for developers.&lt;/p&gt;
&lt;p&gt;There are other ways to transfer data between two EC2 instances. For example, you can use AWS EFS to transfer data between two EC2 instances. But AWS EFS is a file storage service for use with Amazon EC2 instances in the AWS Cloud. It provides a simple, scalable, fully managed elastic NFS file system for use with Linux-based workloads.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;You need to have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI installed and configured&lt;/li&gt;
&lt;li&gt;IAM user with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonEC2FullAccess&lt;/li&gt;
&lt;li&gt;AmazonS3FullAccess&lt;/li&gt;
&lt;li&gt;AmazonVPCFullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create VPC&lt;/h2&gt;
&lt;h3&gt;Step 1: Create VPC&lt;/h3&gt;
&lt;p&gt;To create a VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a VPC
AWS_VPC=$(aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --query &amp;#39;Vpc.VpcId&amp;#39; \
  --output text)

# Add a name tag to the VPC
aws ec2 create-tags \
  --resources $AWS_VPC \
  --tags Key=Name,Value=aws-vpc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-vpc&lt;/code&gt; - Create a VPC&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr-block&lt;/code&gt; - The IPv4 network range for the VPC, in CIDR notation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Modify your custom VPC and enable DNS hostname support, and DNS support&lt;/h3&gt;
&lt;p&gt;To modify your custom VPC and enable DNS hostname support, and DNS support, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable DNS hostnames
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-hostnames &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;

# Enable DNS support
aws ec2 modify-vpc-attribute \
  --vpc-id $AWS_VPC \
  --enable-dns-support &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 modify-vpc-attribute&lt;/code&gt; - Modifies the specified attribute of the specified VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--enable-dns-hostnames&lt;/code&gt; - Indicates whether the instances launched in the VPC get DNS hostnames.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--enable-dns-support&lt;/code&gt; - Indicates whether DNS resolution is supported for the VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Create a Public Subnet&lt;/h3&gt;
&lt;p&gt;To create a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a public subnet
AWS_PUBLIC_SUBNET=$(aws ec2 create-subnet \
  --vpc-id $AWS_VPC \
  --cidr-block 10.0.1.0/24 \
  --query &amp;#39;Subnet.SubnetId&amp;#39; \
  --output text)

# Add a name tag to the public subnet
aws ec2 create-tags \
  --resources $AWS_PUBLIC_SUBNET \
  --tags Key=Name,Value=aws-public-subnet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-subnet&lt;/code&gt; - Creates a subnet in an existing VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr-block&lt;/code&gt; - The IPv4 network range for the subnet, in CIDR notation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Enable Auto-assign Public IP on the subnet&lt;/h3&gt;
&lt;p&gt;To enable auto-assign public IP on the subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable auto-assign public IP on the subnet
aws ec2 modify-subnet-attribute \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --map-public-ip-on-launch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 modify-subnet-attribute&lt;/code&gt; - Modifies a subnet attribute.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; - The ID of the subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--map-public-ip-on-launch&lt;/code&gt; - Specify true to indicate that network interfaces created in the specified subnet should be assigned a public IPv4 address.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Create an Internet Gateway&lt;/h3&gt;
&lt;p&gt;To create an Internet Gateway, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an Internet Gateway
AWS_INTERNET_GATEWAY=$(aws ec2 create-internet-gateway \
  --query &amp;#39;InternetGateway.InternetGatewayId&amp;#39; \
  --output text)

# Add a name tag to the Internet Gateway
aws ec2 create-tags \
  --resources $AWS_INTERNET_GATEWAY \
  --tags Key=Name,Value=aws-internet-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-internet-gateway&lt;/code&gt; - Creates an Internet gateway for use with a VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 6: Attach the Internet Gateway to the VPC&lt;/h3&gt;
&lt;p&gt;To attach the Internet Gateway to the VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the Internet Gateway to the VPC
aws ec2 attach-internet-gateway \
  --internet-gateway-id $AWS_INTERNET_GATEWAY \
  --vpc-id $AWS_VPC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 attach-internet-gateway&lt;/code&gt; - Attaches an Internet gateway to a VPC, enabling connectivity between the Internet and the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--internet-gateway-id&lt;/code&gt; - The ID of the Internet gateway.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 7: Create a Route Table&lt;/h3&gt;
&lt;p&gt;To create a route table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a route table
AWS_ROUTE_TABLE=$(aws ec2 create-route-table \
  --vpc-id $AWS_VPC \
  --query &amp;#39;RouteTable.RouteTableId&amp;#39; \
  --output text)

# Add a name tag to the route table
aws ec2 create-tags \
  --resources $AWS_ROUTE_TABLE \
  --tags Key=Name,Value=aws-route-table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-route-table&lt;/code&gt; - Creates a route table for the specified VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 8: Create a custom route table association&lt;/h3&gt;
&lt;p&gt;To create a custom route table association, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a custom route table association
aws ec2 associate-route-table \
  --subnet-id $AWS_PUBLIC_SUBNET \
  --route-table-id $AWS_ROUTE_TABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 associate-route-table&lt;/code&gt; - Associates a subnet with a route table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; - The ID of the subnet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--route-table-id&lt;/code&gt; - The ID of the route table.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 9: Associate the subnet with route table, making it a public subnet&lt;/h3&gt;
&lt;p&gt;To associate the subnet with route table, making it a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the subnet with route table, making it a public subnet
aws ec2 create-route \
  --route-table-id $AWS_ROUTE_TABLE \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id $AWS_INTERNET_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-route&lt;/code&gt; - Creates a route in a route table within a VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--route-table-id&lt;/code&gt; - The ID of the route table for the route.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--destination-cidr-block&lt;/code&gt; - The IPv4 CIDR address block used for the destination match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--gateway-id&lt;/code&gt; - The ID of an Internet gateway or virtual private gateway attached to your VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 10: Create a Security Group&lt;/h3&gt;
&lt;p&gt;To create a security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a security group
AWS_SECURITY_GROUP=$(aws ec2 create-security-group \
  --group-name aws-security-group \
  --description &amp;quot;AWS Security Group&amp;quot; \
  --vpc-id $AWS_VPC \
  --query &amp;#39;GroupId&amp;#39; \
  --output text)

# Add a name tag to the security group
aws ec2 create-tags \
  --resources $AWS_SECURITY_GROUP \
  --tags Key=Name,Value=aws-security-group
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-security-group&lt;/code&gt; - Creates a security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--group-name&lt;/code&gt; - The name of the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--description&lt;/code&gt; - A description for the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--vpc-id&lt;/code&gt; - The ID of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to apply to the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 11: Add a rule to the security group&lt;/h3&gt;
&lt;p&gt;To add a rule to the security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add a rule to the security group

# Add SSH rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 22 \
--cidr 0.0.0.0/0 \
--output text

# Add HTTP rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 80 \
--cidr 0.0.0.0/0 \
--output text

# Add HTTPS rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 443 \
--cidr 0.0.0.0/0 \
--output text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 authorize-security-group-ingress&lt;/code&gt; - Adds one or more ingress rules to a security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--group-id&lt;/code&gt; - The ID of the security group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--protocol&lt;/code&gt; - The IP protocol name or number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--port&lt;/code&gt; - The port number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--cidr&lt;/code&gt; - The IPv4 CIDR range.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create an S3 Bucket&lt;/h2&gt;
&lt;h3&gt;Step 1: Create an S3 Bucket&lt;/h3&gt;
&lt;p&gt;To create an S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_S3_BUCKET_NAME=aws-s3-bucket-$(date +%s)
# Create an S3 bucket
aws s3 mb s3://$AWS_S3_BUCKET_NAME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 mb&lt;/code&gt; - Creates an S3 bucket.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://$AWS_S3_BUCKET_NAME&lt;/code&gt; - The name of the bucket to create.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create a Two EC2 Instances&lt;/h2&gt;
&lt;h3&gt;Step 1: Get the latest AMI ID&lt;/h3&gt;
&lt;p&gt;To get the latest AMI ID, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the latest AMI ID
AWS_AMI=$(aws ec2 describe-images \
  --owners &amp;#39;amazon&amp;#39; \
  --filters &amp;#39;Name=name,Values=amzn2-ami-hvm-2.0.*&amp;#39; \
  &amp;#39;Name=state,Values=available&amp;#39; \
  --query &amp;#39;sort_by(Images, &amp;amp;CreationDate)[-1].[ImageId]&amp;#39; \
  --output &amp;#39;text&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 describe-images&lt;/code&gt; - Describes one or more of the images (AMIs, AKIs, and ARIs) available to you.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--owners&lt;/code&gt; - Filters the images by the owner.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--filters&lt;/code&gt; - The filters to apply to the images.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Create a Key Pair&lt;/h3&gt;
&lt;p&gt;To create a key pair, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a key pair
aws ec2 create-key-pair \
--key-name aws-key-pair \
--query &amp;#39;KeyMaterial&amp;#39; \
--output text &amp;gt; aws-key-pair.pem

# Change the permission of the key pair
chmod 400 aws-key-pair.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-key-pair&lt;/code&gt; - Creates a 2048-bit RSA key pair with the specified name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-name&lt;/code&gt; - The name for the key pair.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chmod 400 aws-key-pair.pem&lt;/code&gt; - Changes the permission of the key pair, making it read-only.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Create a User Data Script&lt;/h3&gt;
&lt;p&gt;To create a user data script, that will &lt;code&gt;cron&lt;/code&gt; a script to run every minute and sync from and to the S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a user data script
cat &amp;lt;&amp;lt;EOF &amp;gt; user-data.sh
#!/bin/bash

# Update the system
yum update -y

# Install Apache
sudo yum install httpd -y
sudo systemctl start httpd
sudo systemctl enable httpd

# Create a cron job
chmod 600 /etc/crontab

# Create a script to sync from and to the S3 bucket
cat &amp;lt;&amp;lt;EOT1 &amp;gt; /root/sync.sh
#!/bin/bash

# Sync from var/www/html to S3 bucket
cd /var/www/html
aws s3 sync . s3://$AWS_S3_BUCKET_NAME

# Sync from S3 bucket to var/www/html
cd /var/www/html
aws s3 sync s3://$AWS_S3_BUCKET_NAME .
EOT1

# Make the script executable
chmod +x /root/sync.sh

# Add the script to the cron job
echo &amp;quot;* * * * * root /root/sync.sh&amp;quot; &amp;gt;&amp;gt; /etc/crontab

# Create script that creates a random files
cat &amp;lt;&amp;lt;EOF2 &amp;gt; /root/create-random-files.sh
#!/bin/bash

# Create a random file
cd /var/www/html
RANDOM_FILE_NAME=$(cat /dev/urandom | tr -dc &amp;#39;a-zA-Z0-9&amp;#39; | fold -w 32 | head -n 1)
touch random-file-$RANDOM_FILE_NAME.txt
EOF2

# Make the script executable
chmod +x /root/create-random-files.sh

# Create a cron job that runs the script every 2 minutes
echo &amp;quot;*/2 * * * * root /root/create-random-files.sh&amp;quot; &amp;gt;&amp;gt; /etc/crontab

# Restart the cron service
systemctl restart crond
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF &amp;gt; user-data.sh&lt;/code&gt; - Creates a file named &lt;code&gt;user-data.sh&lt;/code&gt; and writes the following lines to it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yum update -y&lt;/code&gt; - Updates the system.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo yum install httpd -y&lt;/code&gt; - Installs Apache.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo systemctl start httpd&lt;/code&gt; - Starts Apache.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo systemctl enable httpd&lt;/code&gt; - Enables Apache.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chmod 600 /etc/crontab&lt;/code&gt; - Changes the permission of the &lt;code&gt;crontab&lt;/code&gt; file, making it read-only.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOT1 &amp;gt; /root/sync.sh&lt;/code&gt; - Creates a file named &lt;code&gt;sync.sh&lt;/code&gt; and writes the following lines to it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aws s3 sync . s3://$AWS_S3_BUCKET_NAME&lt;/code&gt; - Syncs the files from the current directory to the S3 bucket.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aws s3 sync s3://$AWS_S3_BUCKET_NAME .&lt;/code&gt; - Syncs the files from the S3 bucket to the current directory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chmod +x /root/sync.sh&lt;/code&gt; - Makes the &lt;code&gt;sync.sh&lt;/code&gt; script executable.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;echo &amp;quot;* * * * * root /root/sync.sh&amp;quot; &amp;gt;&amp;gt; /etc/crontab&lt;/code&gt; - Adds the &lt;code&gt;sync.sh&lt;/code&gt; script to the &lt;code&gt;crontab&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF2 &amp;gt; /root/create-random-files.sh&lt;/code&gt; - Creates a file named &lt;code&gt;create-random-files.sh&lt;/code&gt; and writes the following lines to it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd /var/www/html&lt;/code&gt; - Changes the current directory to &lt;code&gt;/var/www/html&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RANDOM_FILE_NAME=$(cat /dev/urandom | tr -dc &amp;#39;a-zA-Z0-9&amp;#39; | fold -w 32 | head -n 1)&lt;/code&gt; - Creates a random file name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;touch random-file-$RANDOM_FILE_NAME.txt&lt;/code&gt; - Creates a random file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chmod +x /root/create-random-files.sh&lt;/code&gt; - Makes the &lt;code&gt;create-random-files.sh&lt;/code&gt; script executable.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;echo &amp;quot;*/2 * * * * root /root/create-random-files.sh&amp;quot; &amp;gt;&amp;gt; /etc/crontab&lt;/code&gt; - Adds the &lt;code&gt;create-random-files.sh&lt;/code&gt; script to the &lt;code&gt;crontab&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl restart crond&lt;/code&gt; - Restarts the &lt;code&gt;crond&lt;/code&gt; service.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Create a Two EC2 Instances&lt;/h3&gt;
&lt;p&gt;To create two EC2 instances, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create two EC2 instances
AWS_EC2_INSTANCE_1=$(aws ec2 run-instances \
--image-id $AWS_AMI \
--instance-type t2.micro \
--key-name aws-key-pair \
--monitoring &amp;quot;Enabled=false&amp;quot; \
--security-group-ids $AWS_SECURITY_GROUP \
--subnet-id $AWS_PUBLIC_SUBNET \
--user-data file://user-data.sh \
--query &amp;#39;Instances[0].InstanceId&amp;#39; \
--output text)

AWS_EC2_INSTANCE_2=$(aws ec2 run-instances \
--image-id $AWS_AMI \
--instance-type t2.micro \
--key-name aws-key-pair \
--monitoring &amp;quot;Enabled=false&amp;quot; \
--security-group-ids $AWS_SECURITY_GROUP \
--subnet-id $AWS_PUBLIC_SUBNET \
--user-data file://user-data.sh \
--query &amp;#39;Instances[0].InstanceId&amp;#39; \
--output text)

# Add a tag to the instances
aws ec2 create-tags \
--resources $AWS_EC2_INSTANCE_1 \
--tags Key=Name,Value=ec2-instance-1

aws ec2 create-tags \
--resources $AWS_EC2_INSTANCE_2 \
--tags Key=Name,Value=ec2-instance-2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 run-instances&lt;/code&gt; - Launches the specified number of instances using an AMI for which you have permissions.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--image-id&lt;/code&gt; - The ID of the AMI.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-type&lt;/code&gt; - The instance type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-name&lt;/code&gt; - The name of the key pair.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--monitoring&lt;/code&gt; - Enables detailed monitoring.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--security-group-ids&lt;/code&gt; - The IDs of the security groups.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--subnet-id&lt;/code&gt; - The ID of the subnet in which to launch the instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--user-data&lt;/code&gt; - The user data to make available to the instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aws ec2 create-tags&lt;/code&gt; - Adds or overwrites one or more tags for the specified resources or resource types.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resources&lt;/code&gt; - The IDs of the resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tags&lt;/code&gt; - The tags to add or overwrite for the specified resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Check the status of the EC2 instances&lt;/h3&gt;
&lt;p&gt;To check the status of the EC2 instances, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Check the status of the EC2 instances
aws ec2 describe-instances \
--instance-ids $AWS_EC2_INSTANCE_1 $AWS_EC2_INSTANCE_2 \
--query &amp;#39;Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress]&amp;#39; \
--output table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws ec2 describe-instances&lt;/code&gt; - Describes one or more of your instances.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--instance-ids&lt;/code&gt; - The IDs of the instances.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--query&lt;/code&gt; - The JMESPath query that is applied to the output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt; - The output format of the command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, you learned how to create a highly available web application using AWS. You also learned how to create a VPC, subnets, and security groups. You also learned how to create an S3 bucket and EC2 instances. You also learned how to create a cron job that syncs the S3 bucket to the Apache directory and vice versa.&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html&quot;&gt;Amazon S3 User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&quot;&gt;Amazon VPC User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS Command Line Interface (CLI) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/sync.html&quot;&gt;AWS CLI Command Reference - s3 sync&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/index.html&quot;&gt;AWS CLI Command Reference - ec2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.man7.org/linux/man-pages/man5/crontab.5.html&quot;&gt;Scheduling Tasks with Cron&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html&quot;&gt;User data and shell scripts for EC2 instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html&quot;&gt;Creating an S3 bucket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html&quot;&gt;Working with Amazon S3 Buckets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html&quot;&gt;Security groups for your VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html&quot;&gt;Tutorial: Installing a LAMP Web Server on Amazon Linux 2&lt;/a&gt; (Relevant for Apache setup)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/s3/transfer-data/&quot;&gt;Transferring data to and from Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>EC2</category><category>S3</category><category>Data Transfer</category><category>AWS CLI</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0024-how-to-connect-a-two-ec2-instances-data-transfer-using-aws-cli-without-aws-efs/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Create a AWS S3 Bucket Using AWS CLI</title><link>https://mkabumattar.com/blog/post/how-to-create-a-aws-s3-bucket-using-aws-cli/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-create-a-aws-s3-bucket-using-aws-cli/</guid><description>In this post, I will show you how to create a AWS S3 bucket using AWS CLI.</description><pubDate>Fri, 11 Nov 2022 16:30:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, I will show you how to create a AWS S3 bucket using AWS CLI.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;You need to have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI installed and configured&lt;/li&gt;
&lt;li&gt;AWS S3 bucket name&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;AWS S3 Bucket&lt;/h2&gt;
&lt;h3&gt;Step 1: Create AWS S3 Bucket&lt;/h3&gt;
&lt;p&gt;To create a AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 mb s3://&amp;lt;BUCKET_NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 mb&lt;/code&gt; - Create a bucket&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;&lt;/code&gt; - Bucket name&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;&lt;ul&gt;
&lt;li&gt;The bucket name must be unique across all existing bucket names in Amazon S3.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--region&lt;/code&gt; option to specify the region where the bucket will
be created.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--acl&lt;/code&gt; option to specify the access control list (ACL) for
the bucket.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--create-bucket-configuration&lt;/code&gt; option to specify the bucket configuration.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--grants&lt;/code&gt; option to specify the grantee and permission for each grantee.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Notice&gt;&lt;h3&gt;Step 2: List AWS S3 Buckets&lt;/h3&gt;
&lt;p&gt;To list all AWS S3 buckets, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 ls&lt;/code&gt; - List all buckets&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Upload File to AWS S3 Bucket&lt;/h3&gt;
&lt;p&gt;To upload a file to AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 cp &amp;lt;FILE_PATH&amp;gt; s3://&amp;lt;BUCKET_NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 cp&lt;/code&gt; - Copy an object&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;FILE_PATH&amp;gt;&lt;/code&gt; - File path in your local machine&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;&lt;/code&gt; - Bucket name where the file will be uploaded&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Download File from AWS S3 Bucket&lt;/h3&gt;
&lt;p&gt;To download a file from AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 cp s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;FILE_NAME&amp;gt; &amp;lt;FILE_PATH&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 cp&lt;/code&gt; - Copy an object&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;FILE_NAME&amp;gt;&lt;/code&gt; - Bucket name and file name where the file will be downloaded from&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;FILE_PATH&amp;gt;&lt;/code&gt; - File path in your local machine&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Sync Local Directory with AWS S3 Bucket&lt;/h3&gt;
&lt;p&gt;To sync a local directory with AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 sync &amp;lt;LOCAL_DIRECTORY_PATH&amp;gt; s3://&amp;lt;BUCKET_NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 sync&lt;/code&gt; - Sync a local directory with a S3 bucket&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;LOCAL_DIRECTORY_PATH&amp;gt;&lt;/code&gt; - Local directory path in your local machine&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;&lt;/code&gt; - Bucket name where the local directory will be synced with&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 6: Sync AWS S3 Bucket with Local Directory&lt;/h3&gt;
&lt;p&gt;To sync a AWS S3 bucket with local directory, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 sync s3://&amp;lt;BUCKET_NAME&amp;gt; &amp;lt;LOCAL_DIRECTORY_PATH&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 sync&lt;/code&gt; - Sync a S3 bucket with a local directory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;&lt;/code&gt; - Bucket name where the local directory will be synced with&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;LOCAL_DIRECTORY_PATH&amp;gt;&lt;/code&gt; - Local directory path in your local machine&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 7: List Files in AWS S3 Bucket&lt;/h3&gt;
&lt;p&gt;To list all files in a AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 ls s3://&amp;lt;BUCKET_NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 ls&lt;/code&gt; - List all objects in a bucket&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;&lt;/code&gt; - Bucket name&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 8: Move File in AWS S3 Bucket&lt;/h3&gt;
&lt;p&gt;To move a file in a AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 mv s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;FILE_NAME&amp;gt; s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;NEW_FILE_NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 mv&lt;/code&gt; - Move an object&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;FILE_NAME&amp;gt;&lt;/code&gt; - Bucket name and file name where the file will be moved from&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;NEW_FILE_NAME&amp;gt;&lt;/code&gt; - Bucket name and new file name where the file will be moved to&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 9: Presign URL for AWS S3 Bucket&lt;/h3&gt;
&lt;p&gt;To presign a URL for a AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 presign s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;FILE_NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 presign&lt;/code&gt; - Generate a presigned URL for an Amazon S3 object or a bucket&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;FILE_NAME&amp;gt;&lt;/code&gt; - Bucket name and file name where the file will be presigned&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;&lt;ul&gt;
&lt;li&gt;You can use the &lt;code&gt;--expires-in&lt;/code&gt; option to specify the number of seconds before the presigned URL expires.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--region&lt;/code&gt; option to specify the region where the bucket is located.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--signature-version&lt;/code&gt; option to specify the signature version to use when signing the URL.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--version-id&lt;/code&gt; option to specify the version ID of the object that the presigned URL will be used to access.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Notice&gt;&lt;h3&gt;Step 10: Delete File from AWS S3 Bucket&lt;/h3&gt;
&lt;p&gt;To delete a file from a AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 rm s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;FILE_NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 rm&lt;/code&gt; - Remove an object&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;/&amp;lt;FILE_NAME&amp;gt;&lt;/code&gt; - Bucket name and file name where the file will be deleted from&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 11: Delete AWS S3 Bucket&lt;/h3&gt;
&lt;p&gt;To delete a AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 rb s3://&amp;lt;BUCKET_NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 rb&lt;/code&gt; - Remove a bucket&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;&lt;/code&gt; - Bucket name&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;&lt;ul&gt;
&lt;li&gt;You can use the &lt;code&gt;--force&lt;/code&gt; option to delete a non-empty bucket.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--region&lt;/code&gt; option to specify the region where the bucket is located.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--versioning&lt;/code&gt; option to delete all objects (including all object versions and delete markers) in the bucket.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Notice&gt;&lt;h3&gt;Step 12: Static Website Hosting&lt;/h3&gt;
&lt;p&gt;To host a static website on AWS S3 bucket, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws s3 website s3://&amp;lt;BUCKET_NAME&amp;gt; --index-document &amp;lt;INDEX_DOCUMENT&amp;gt; --error-document &amp;lt;ERROR_DOCUMENT&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aws s3 website&lt;/code&gt; - Set the configuration of a bucket for website hosting&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s3://&amp;lt;BUCKET_NAME&amp;gt;&lt;/code&gt; - Bucket name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--index-document&lt;/code&gt; - The name of the index document (for example, index.html)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--error-document&lt;/code&gt; - The name of the error document (for example, error.html)&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;&lt;ul&gt;
&lt;li&gt;You can use the &lt;code&gt;--region&lt;/code&gt; option to specify the region where the bucket is located.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--website-configuration&lt;/code&gt; option to specify the website configuration.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;--remove&lt;/code&gt; option to remove the website configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/Notice&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, you learned how to use the AWS CLI to manage AWS S3 buckets. You also learned how to upload, download, sync, list, move, presign, and delete files in AWS S3 buckets.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html&quot;&gt;Amazon S3 User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/index.html&quot;&gt;AWS CLI Command Reference - s3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/index.html&quot;&gt;AWS CLI Command Reference - s3api&lt;/a&gt; (for more granular S3 operations)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html&quot;&gt;Working with Amazon S3 Buckets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/UploadingObjects.html&quot;&gt;Uploading Objects to Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/download-objects.html&quot;&gt;Downloading an Object from Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-sync&quot;&gt;Syncing Folders with Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/ListingKeysUsingAPIs.html&quot;&gt;Listing Keys in an Amazon S3 Bucket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html&quot;&gt;Generating a Presigned URL for an S3 Object&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/DeletingObjects.html&quot;&gt;Deleting Objects from Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-bucket.html&quot;&gt;Deleting an S3 Bucket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteHosting.html&quot;&gt;Hosting a Static Website on Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS CLI User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html&quot;&gt;Bucket Naming Rules - Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>S3</category><category>AWS CLI</category><category>Cloud Storage</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0023-how-to-create-a-aws-s3-bucket-using-aws-cli/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Create a DynamoDB Table Using AWS CLI</title><link>https://mkabumattar.com/blog/post/how-to-create-a-dynamodb-table-using-aws-cli/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-create-a-dynamodb-table-using-aws-cli/</guid><description>In this article, we will learn how to create a DynamoDB table using AWS CLI. We will also learn how to add items to the table and how to query the table.</description><pubDate>Thu, 10 Nov 2022 20:18:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this article, we will learn how to create a DynamoDB table using AWS CLI. We will also learn how to add items to the table and how to query the table.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow this article, you need to have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI&lt;/li&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;AWS IAM User with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonDynamoDBFullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AWS CLI configured with the IAM User&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create a DynamoDB Table&lt;/h2&gt;
&lt;h3&gt;Step 1: Create a DynamoDB Table&lt;/h3&gt;
&lt;p&gt;To create a DynamoDB table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb create-table \
    --table-name MyTable \
    --attribute-definitions \
        AttributeName=Id,AttributeType=S \
    --key-schema \
        AttributeName=Id,KeyType=HASH \
    --provisioned-throughput \
        ReadCapacityUnits=1,WriteCapacityUnits=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--table-name&lt;/code&gt;: The name of the table to create.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--attribute-definitions&lt;/code&gt;: An array of attributes that describe the key schema for the table and indexes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-schema&lt;/code&gt;: Specifies the attributes that make up the primary key for a table or an index.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--provisioned-throughput&lt;/code&gt;: The provisioned throughput settings for the table or index.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: List the Tables&lt;/h3&gt;
&lt;p&gt;To list the tables, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb list-tables
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Insert Items to the Table&lt;/h3&gt;
&lt;h4&gt;Step 3.1: Insert an Item Using AWS CLI&lt;/h4&gt;
&lt;p&gt;To insert items to the table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb put-item \
    --table-name MyTable \
    --item \
        &amp;#39;{&amp;quot;Id&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;1&amp;quot;}, &amp;quot;Name&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;John Doe&amp;quot;}}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--item&lt;/code&gt;: A map of attribute name to attribute values, representing the primary key of the item to be retrieved.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 3.2: Insert Multiple Items Using AWS CLI&lt;/h4&gt;
&lt;p&gt;To insert multiple items to the table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb batch-write-item \
    --request-items \
        &amp;#39;{&amp;quot;MyTable&amp;quot;: [{&amp;quot;PutRequest&amp;quot;: {&amp;quot;Item&amp;quot;: {&amp;quot;Id&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;2&amp;quot;}, &amp;quot;Name&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;Jane Doe&amp;quot;}}}}]}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--request-items&lt;/code&gt;: A map of one or more table names and, for each table, a list of operations to be performed (&lt;code&gt;DeleteRequest&lt;/code&gt; or &lt;code&gt;PutRequest&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 3.3: Insert Items From a JSON File Using AWS CLI&lt;/h4&gt;
&lt;p&gt;Create a JSON file with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# create a JSON file
touch items.json

# open the file
vim items.json
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;MyTable&amp;quot;: [
    {
      &amp;quot;PutRequest&amp;quot;: {
        &amp;quot;Item&amp;quot;: {
          &amp;quot;Id&amp;quot;: {
            &amp;quot;S&amp;quot;: &amp;quot;3&amp;quot;
          },
          &amp;quot;Name&amp;quot;: {
            &amp;quot;S&amp;quot;: &amp;quot;John Doe&amp;quot;
          }
        }
      }
    },
    {
      &amp;quot;PutRequest&amp;quot;: {
        &amp;quot;Item&amp;quot;: {
          &amp;quot;Id&amp;quot;: {
            &amp;quot;S&amp;quot;: &amp;quot;4&amp;quot;
          },
          &amp;quot;Name&amp;quot;: {
            &amp;quot;S&amp;quot;: &amp;quot;Jane Doe&amp;quot;
          }
        }
      }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To insert items from a JSON file to the table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb batch-write-item \
    --request-items file://items.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--request-items&lt;/code&gt;: A map of one or more table names and, for each table, a list of operations to be performed (&lt;code&gt;DeleteRequest&lt;/code&gt; or &lt;code&gt;PutRequest&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;file://items.json&lt;/code&gt;: The path to the JSON file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 4: Query the Table&lt;/h3&gt;
&lt;h4&gt;Step 4.1: Query the Table Using AWS CLI&lt;/h4&gt;
&lt;p&gt;To query the table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb query \
    --table-name MyTable \
    --key-condition-expression &amp;quot;Id = :id&amp;quot; \
    --expression-attribute-values  &amp;#39;{&amp;quot;:id&amp;quot;:{&amp;quot;S&amp;quot;:&amp;quot;1&amp;quot;}}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--key-condition-expression&lt;/code&gt;: A condition that evaluates the query results and returns only the desired values.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--expression-attribute-values&lt;/code&gt;: One or more values that can be substituted in an expression.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 4.2: Query the Table Using AWS CLI and Output to a JSON File&lt;/h4&gt;
&lt;p&gt;To query the table and output the result to a JSON file, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb query \
    --table-name MyTable \
    --key-condition-expression &amp;quot;Id = :id&amp;quot; \
    --expression-attribute-values  &amp;#39;{&amp;quot;:id&amp;quot;:{&amp;quot;S&amp;quot;:&amp;quot;1&amp;quot;}}&amp;#39; \
    --output json &amp;gt; result.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--output&lt;/code&gt;: The output format of the query result.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt; result.json&lt;/code&gt;: The path to the JSON file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Create a Global Secondary Index&lt;/h3&gt;
&lt;p&gt;Global Secondary is a secondary index with a partition key and a sort key that can be different from those on the table. You can query the index using the partition key and sort key, or you can query the index using only the partition key.&lt;/p&gt;
&lt;h4&gt;Step 5.1: Create a Global Secondary Index Using AWS CLI&lt;/h4&gt;
&lt;p&gt;To create a global secondary index, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb update-table \
    --table-name MyTable \
    --attribute-definitions \
        AttributeName=Name,AttributeType=S \
    --global-secondary-index-updates \
        &amp;#39;[{&amp;quot;Create&amp;quot;: {&amp;quot;IndexName&amp;quot;: &amp;quot;NameIndex&amp;quot;, &amp;quot;KeySchema&amp;quot;: [{&amp;quot;AttributeName&amp;quot;: &amp;quot;Name&amp;quot;, &amp;quot;KeyType&amp;quot;: &amp;quot;HASH&amp;quot;}], &amp;quot;Projection&amp;quot;: {&amp;quot;ProjectionType&amp;quot;: &amp;quot;ALL&amp;quot;}, &amp;quot;ProvisionedThroughput&amp;quot;: {&amp;quot;ReadCapacityUnits&amp;quot;: 1, &amp;quot;WriteCapacityUnits&amp;quot;: 1}}}]&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--attribute-definitions&lt;/code&gt;: An array of attributes that describe the key schema for the table and indexes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--global-secondary-index-updates&lt;/code&gt;: An array of one or more global secondary indexes to be updated on the table.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 6: Remove the Global Secondary Index&lt;/h3&gt;
&lt;h4&gt;Step 6.1: Remove the Global Secondary Index Using AWS CLI&lt;/h4&gt;
&lt;p&gt;To remove the global secondary index, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb update-table \
    --table-name MyTable \
    --global-secondary-index-updates \
        &amp;#39;[{&amp;quot;Delete&amp;quot;: {&amp;quot;IndexName&amp;quot;: &amp;quot;NameIndex&amp;quot;}}]&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--global-secondary-index-updates&lt;/code&gt;: An array of one or more global secondary indexes to be updated on the table.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 7: Create Two DynamoDB Tables With Relationships&lt;/h3&gt;
&lt;h4&gt;Step 7.1: Create the First Table&lt;/h4&gt;
&lt;p&gt;To create the first table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb create-table \
    --table-name User \
    --attribute-definitions \
        AttributeName=Id,AttributeType=S \
    --key-schema \
        AttributeName=Id,KeyType=HASH \
    --provisioned-throughput \
        ReadCapacityUnits=1,WriteCapacityUnits=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--table-name&lt;/code&gt;: The name of the table to be created.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--attribute-definitions&lt;/code&gt;: An array of attributes that describe the key schema for the table and indexes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-schema&lt;/code&gt;: Specifies the attributes that make up the primary key for a table or an index.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--provisioned-throughput&lt;/code&gt;: The provisioned throughput settings for the table or index.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 7.2: Create the Second Table&lt;/h4&gt;
&lt;p&gt;To create the second table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb create-table \
    --table-name Post \
    --attribute-definitions \
        AttributeName=Id,AttributeType=S \
        AttributeName=UserId,AttributeType=S \
    --key-schema \
        AttributeName=Id,KeyType=HASH \
    --global-secondary-indexes \
        &amp;#39;[{&amp;quot;IndexName&amp;quot;: &amp;quot;UserIdIndex&amp;quot;, &amp;quot;KeySchema&amp;quot;: [{&amp;quot;AttributeName&amp;quot;: &amp;quot;UserId&amp;quot;, &amp;quot;KeyType&amp;quot;: &amp;quot;HASH&amp;quot;}], &amp;quot;Projection&amp;quot;: {&amp;quot;ProjectionType&amp;quot;: &amp;quot;ALL&amp;quot;}, &amp;quot;ProvisionedThroughput&amp;quot;: {&amp;quot;ReadCapacityUnits&amp;quot;: 1, &amp;quot;WriteCapacityUnits&amp;quot;: 1}}]&amp;#39; \
    --provisioned-throughput \
        ReadCapacityUnits=1,WriteCapacityUnits=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--table-name&lt;/code&gt;: The name of the table to be created.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--attribute-definitions&lt;/code&gt;: An array of attributes that describe the key schema for the table and indexes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-schema&lt;/code&gt;: Specifies the attributes that make up the primary key for a table or an index.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--global-secondary-indexes&lt;/code&gt;: One or more global secondary indexes (the maximum is 20) to be created on the table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--provisioned-throughput&lt;/code&gt;: The provisioned throughput settings for the table or index.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 7.3: Add Items to the First Table&lt;/h4&gt;
&lt;p&gt;To add items to the first table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb batch-write-item \
    --request-items \
        &amp;#39;{&amp;quot;User&amp;quot;: [{&amp;quot;PutRequest&amp;quot;: {&amp;quot;Item&amp;quot;: {&amp;quot;Id&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;1&amp;quot;}, &amp;quot;Name&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;John Doe&amp;quot;}}}}]}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--request-items&lt;/code&gt;: A map of one or more table names and, for each table, a list of operations to be performed (&lt;code&gt;DeleteRequest&lt;/code&gt; or &lt;code&gt;PutRequest&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 7.4: Add Items to the Second Table&lt;/h4&gt;
&lt;p&gt;To add items to the second table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb batch-write-item \
    --request-items \
        &amp;#39;{&amp;quot;Post&amp;quot;: [{&amp;quot;PutRequest&amp;quot;: {&amp;quot;Item&amp;quot;: {&amp;quot;Id&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;1&amp;quot;}, &amp;quot;UserId&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;1&amp;quot;}, &amp;quot;Title&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;Hello World&amp;quot;}}}}]}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--request-items&lt;/code&gt;: A map of one or more table names and, for each table, a list of operations to be performed (&lt;code&gt;DeleteRequest&lt;/code&gt; or &lt;code&gt;PutRequest&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 7.5: Query the Second Table Using AWS CLI&lt;/h4&gt;
&lt;p&gt;To query the second table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb query \
    --table-name Post \
    --index-name UserIdIndex \
    --key-condition-expression &amp;quot;UserId = :userId&amp;quot; \
    --expression-attribute-values  &amp;#39;{&amp;quot;:userId&amp;quot;:{&amp;quot;S&amp;quot;:&amp;quot;1&amp;quot;}}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--table-name&lt;/code&gt;: The name of the table containing the requested items.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--index-name&lt;/code&gt;: The name of a global secondary index to be queried.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-condition-expression&lt;/code&gt;: A condition that evaluates the query results and returns only the desired values.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--expression-attribute-values&lt;/code&gt;: One or more values that can be substituted in an expression.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 8: Create a DynamoDB Table With a Local Secondary Index&lt;/h3&gt;
&lt;h4&gt;Step 8.1: Create the Table&lt;/h4&gt;
&lt;p&gt;To create the table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb create-table \
    --table-name MyTable \
    --attribute-definitions \
        AttributeName=Id,AttributeType=S \
        AttributeName=Name,AttributeType=S \
    --key-schema \
        AttributeName=Id,KeyType=HASH \
        AttributeName=Name,KeyType=RANGE \
    --local-secondary-indexes \
        &amp;#39;[{&amp;quot;IndexName&amp;quot;: &amp;quot;NameIndex&amp;quot;, &amp;quot;KeySchema&amp;quot;: [{&amp;quot;AttributeName&amp;quot;: &amp;quot;Id&amp;quot;, &amp;quot;KeyType&amp;quot;: &amp;quot;HASH&amp;quot;}, {&amp;quot;AttributeName&amp;quot;: &amp;quot;Name&amp;quot;, &amp;quot;KeyType&amp;quot;: &amp;quot;RANGE&amp;quot;}], &amp;quot;Projection&amp;quot;: {&amp;quot;ProjectionType&amp;quot;: &amp;quot;ALL&amp;quot;}}]&amp;#39; \
    --provisioned-throughput \
        ReadCapacityUnits=1,WriteCapacityUnits=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--table-name&lt;/code&gt;: The name of the table to be created.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--attribute-definitions&lt;/code&gt;: An array of attributes that describe the key schema for the table and indexes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-schema&lt;/code&gt;: Specifies the attributes that make up the primary key for a table or an index.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--local-secondary-indexes&lt;/code&gt;: One or more local secondary indexes (the maximum is 5) to be created on the table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--provisioned-throughput&lt;/code&gt;: The provisioned throughput settings for the table or index.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 8.2: Add Items to the Table&lt;/h4&gt;
&lt;p&gt;To add items to the table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb batch-write-item \
    --request-items \
        &amp;#39;{&amp;quot;MyTable&amp;quot;: [{&amp;quot;PutRequest&amp;quot;: {&amp;quot;Item&amp;quot;: {&amp;quot;Id&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;1&amp;quot;}, &amp;quot;Name&amp;quot;: {&amp;quot;S&amp;quot;: &amp;quot;John Doe&amp;quot;}}}}]}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--request-items&lt;/code&gt;: A map of one or more table names and, for each table, a list of operations to be performed (&lt;code&gt;DeleteRequest&lt;/code&gt; or &lt;code&gt;PutRequest&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 8.3: Query the Table Using AWS CLI&lt;/h4&gt;
&lt;p&gt;To query the table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb query \
    --table-name MyTable \
    --index-name NameIndex \
    --key-condition-expression &amp;quot;Id = :id&amp;quot; \
    --expression-attribute-values  &amp;#39;{&amp;quot;:id&amp;quot;:{&amp;quot;S&amp;quot;:&amp;quot;1&amp;quot;}}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--table-name&lt;/code&gt;: The name of the table containing the requested items.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--index-name&lt;/code&gt;: The name of a local secondary index to be queried.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--key-condition-expression&lt;/code&gt;: A condition that evaluates the query results and returns only the desired values.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--expression-attribute-values&lt;/code&gt;: One or more values that can be substituted in an expression.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 9: Describe a DynamoDB Table Using AWS CLI&lt;/h3&gt;
&lt;p&gt;Describe is used to get information about a table, such as the table status, creation date, and primary key schema.&lt;/p&gt;
&lt;p&gt;To describe a table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb describe-table \
    --table-name MyTable
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 10: Delete a DynamoDB Table Using AWS CLI&lt;/h3&gt;
&lt;p&gt;Delete is used to remove a table and all of its items.&lt;/p&gt;
&lt;p&gt;To delete a table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;aws dynamodb delete-table \
    --table-name MyTable
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, you learned how to use the AWS CLI to create, query, and delete DynamoDB tables. You also learned how to use the AWS CLI to create, query, and delete DynamoDB tables with global and local secondary indexes.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html&quot;&gt;Amazon DynamoDB Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/index.html&quot;&gt;AWS CLI Command Reference - dynamodb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.CLI.html&quot;&gt;Getting Started with DynamoDB and the AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html&quot;&gt;Core Components of Amazon DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html&quot;&gt;Working with Tables in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html&quot;&gt;Working with Items in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html&quot;&gt;Querying Data in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html&quot;&gt;Global Secondary Indexes (GSIs) in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html&quot;&gt;Local Secondary Indexes (LSIs) in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ProvisionedThroughput.html&quot;&gt;Provisioned Throughput in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS CLI User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/create-table.html&quot;&gt;DynamoDB &lt;code&gt;create-table&lt;/code&gt; CLI command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/put-item.html&quot;&gt;DynamoDB &lt;code&gt;put-item&lt;/code&gt; CLI command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/batch-write-item.html&quot;&gt;DynamoDB &lt;code&gt;batch-write-item&lt;/code&gt; CLI command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/query.html&quot;&gt;DynamoDB &lt;code&gt;query&lt;/code&gt; CLI command&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>DynamoDB</category><category>AWS CLI</category><category>NoSQL Databases</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0022-how-to-create-a-dynamodb-table-using-aws-cli/hero.jpg" length="0" type="image/jpeg"/></item><item><title>What is a CI/CD?</title><link>https://mkabumattar.com/blog/post/what-is-a-ci-cd/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/what-is-a-ci-cd/</guid><description>Continuous Integration and Continuous Delivery are two of the most important concepts in DevOps. In this article, we will discuss what is a CI/CD and how it can help you to improve your software development process.</description><pubDate>Wed, 09 Nov 2022 00:38:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Continuous Integration and Continuous Delivery are two of the most important concepts in DevOps. In this article, we will discuss what is a CI/CD and how it can help you to improve your software development process.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CI&lt;/strong&gt; is a software development practice where developers integrate code into a shared repository frequently, preferably several times a day. Each integration can then be verified by an automated build and automated tests. By doing so, you can detect errors quickly, and locate them more easily.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CD&lt;/strong&gt; is a software development practice where developers automatically deploy integrated changes to a software system. By doing so, you can improve software delivery and deployment frequency.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is a CI/CD?&lt;/h2&gt;
&lt;p&gt;CI/CD is a software development practice that requires developers to integrate code into a shared repository several times a day. Then, with the help of automated building and testing, the code is merged into a production branch and deployed to the production environment.&lt;/p&gt;
&lt;h2&gt;Why do we need CI/CD?&lt;/h2&gt;
&lt;p&gt;The main reason for using CI/CD is to reduce the time it takes to release new features to the market. The CI/CD process is a continuous process that allows developers to quickly and easily integrate new code into the production environment. This means that the time it takes to release new features to the market is reduced.&lt;/p&gt;
&lt;h2&gt;What is the difference between CI and CD?&lt;/h2&gt;
&lt;p&gt;The main difference between CI and CD is that CI is a software development practice that requires developers to integrate code into a shared repository several times a day. Then, with the help of automated building and testing, the code is merged into a production branch and deployed to the production environment.&lt;/p&gt;
&lt;p&gt;The &amp;quot;CD&amp;quot; in CI/CD refers to continuous delivery and/or continuous deployment. Continuous delivery is a software development practice where code changes are automatically built, tested, and prepared for a release to production. Continuous deployment is a software development practice where code changes are automatically built, tested, and released to production.&lt;/p&gt;
&lt;p&gt;Continuous delivery usually means a developer’s changes are automatically built, tested, and prepared for release to production. Continuous deployment usually means a developer’s changes are automatically built, tested, and released to production.&lt;/p&gt;
&lt;p&gt;Continuous deployment can be done manually or automatically. Continuous deployment is a software development practice where code changes are automatically built, tested, and released to production.&lt;/p&gt;
&lt;h2&gt;Continuous integration&lt;/h2&gt;
&lt;p&gt;The objective of contemporary application development is to have numerous developers working on various elements of the same app concurrently. The effort that results, however, can be laborious, manual, and time-consuming if a company is set up to integrate all branching source code on one day (referred to as &amp;quot;merge day&amp;quot;) This is so that modifications made to an application by a developer working alone won&amp;#39;t necessarily clash with other changes made concurrently by other developers. Instead of the team deciding on a single cloud-based IDE, this problem might be made worse if each developer customizes their own local integrated development environment (IDE).&lt;/p&gt;
&lt;p&gt;Continuous integration (CI) helps developers merge their code changes into a shared repository several times a day. This allows them to detect errors quickly and locate them more easily. CI also helps to reduce the time it takes to release new features to the market.&lt;/p&gt;
&lt;h2&gt;Continuous delivery&lt;/h2&gt;
&lt;p&gt;Continuous delivery automates the deployment of that verified code to a repository after the automation of builds and unit and integration testing in CI. Therefore, it&amp;#39;s critical that CI be already included in your development pipeline in order to have a successful continuous delivery process. A codebase that is constantly prepared for deployment to a production environment is the aim of continuous delivery.&lt;/p&gt;
&lt;p&gt;Every step of the continuous delivery process is automated, from code merging through application deployment. As a result, it takes less time to provide new features to the market. The operations team may then launch the application into production after that procedure is complete.&lt;/p&gt;
&lt;h2&gt;Continuous deployment&lt;/h2&gt;
&lt;p&gt;Continuous deployment is the last phase of an advanced CI/CD process. Continuous deployment automates the release of an app to production as an extension of continuous delivery, which automates the release of a production-ready build to a code repository. Continuous deployment largely relies on well-designed test automation as there is no manual gate at the pipeline level prior to production.&lt;/p&gt;
&lt;p&gt;Continuous deployment allows a developer&amp;#39;s contribution to a cloud application to be put into use in production right away. The old software development process, which may take weeks or months to finish, is significantly improved by this.&lt;/p&gt;
&lt;h2&gt;CI/CD tools&lt;/h2&gt;
&lt;p&gt;A team may automate development, deployment, and testing with the use of CI/CD systems. Some technologies specialize on continuous testing or related tasks, while others manage development and deployment (CD) and the integration (CI) side. The following are some of the most popular CI/CD tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Jenkins&lt;/strong&gt; is an open-source automation server that can be used to automate all sorts of tasks related to building, testing, and delivering or deploying software. It is written in Java and is available for Windows, Linux, and macOS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Travis CI&lt;/strong&gt; is a hosted, distributed continuous integration service used to build and test software projects hosted at GitHub. It is free for open source projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CircleCI&lt;/strong&gt; is a hosted continuous integration and continuous delivery service used to build and test software projects hosted at GitHub and Bitbucket. It is free for open source projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitLab CI&lt;/strong&gt; is a continuous integration service included with GitLab that runs tests for your projects and notifies you of the results. It is free for open source projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Buddy&lt;/strong&gt; is a continuous integration and deployment platform for developers. It is free for open source projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TeamCity&lt;/strong&gt; is a continuous integration server that can be used to automate the build, test, and release process of software projects. It is free for open source projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bamboo&lt;/strong&gt; is a continuous integration server that can be used to automate the build, test, and release process of software projects. It is free for open source projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and many more...&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we discussed what is a CI/CD and how it can help you to improve your software development process. We also discussed the difference between CI and CD and the tools that can help you to implement CI/CD in your project. I hope you enjoyed this article. If you have any questions or suggestions, please leave a comment below.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.redhat.com/en/topics/devops/what-is-ci-cd&quot;&gt;What is CI/CD? - Red Hat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment&quot;&gt;Continuous integration vs. delivery vs. deployment - Atlassian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://resources.github.com/ci-cd/&quot;&gt;What is CI/CD? - GitHub Resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/ci/introduction/&quot;&gt;CI/CD concepts - GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/devops/continuous-delivery/&quot;&gt;What is Continuous Delivery? - Amazon Web Services (AWS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/&quot;&gt;Jenkins User Documentation - Pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://circleci.com/what-is-ci-cd/&quot;&gt;CircleCI - What is CI/CD?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.travis-ci.com/user/for-beginners/&quot;&gt;Travis CI - What is CI/CD?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/devops/ci-cd&quot;&gt;Google Cloud - What is CI/CD?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/overview/what-is-ci-cd/&quot;&gt;Microsoft Azure - What is CI/CD?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinfowler.com/articles/continuousIntegration.html&quot;&gt;Martin Fowler - Continuous Integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinfowler.com/bliki/ContinuousDelivery.html&quot;&gt;Martin Fowler - Continuous Delivery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devops.com/cicd/&quot;&gt;DevOps.com - CI/CD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://12factor.net/build-release-run&quot;&gt;The Twelve-Factor App - Build, release, run&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>DevOps</category><category>Software Development</category><category>Automation</category><category>CI/CD</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0021-what-is-a-ci-cd/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Setup Nextjs Tailwind CSS Styled Components with TypeScript</title><link>https://mkabumattar.com/blog/post/setup-nextjs-tailwind-css-styled-components-with-typescript/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/setup-nextjs-tailwind-css-styled-components-with-typescript/</guid><description>In this post, we will setup Nextjs Tailwind CSS Styled Components with TypeScript.</description><pubDate>Tue, 08 Nov 2022 00:38:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, we will setup Nextjs Tailwind CSS Styled Components with TypeScript, and we will use the following tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nextjs&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Styled Components&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;You need to have the following tools installed on your system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Yarn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Setup Nextjs App&lt;/h2&gt;
&lt;h3&gt;Step 1: Create a Nextjs app&lt;/h3&gt;
&lt;p&gt;First, we will create a Nextjs app using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a Nextjs app
yarn create next-app nextjs-tailwind-styled-components-typescript
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you will be asked to choose a TypeScript and ESLint, choose the following options:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Choose a TypeScript
✔ Would you like to use TypeScript with this project? … No / Yes # Choose Yes

# Choose a ESLint
✔ Would you like to use ESLint with this project? … No / Yes # Choose Yes
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Go to the Nextjs app directory&lt;/h3&gt;
&lt;p&gt;After creating the Nextjs app, we need to go to the Nextjs app directory using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Go to the Nextjs app directory
cd nextjs-tailwind-styled-components-typescript
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Prepare the Nextjs app&lt;/h3&gt;
&lt;p&gt;First, we need to install the following dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install the following dependencies
yarn add -D eslint-config-prettier eslint-plugin-prettier prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we need to create a &lt;code&gt;.npmrc&lt;/code&gt; file in the root directory of the Nextjs app, and we will add the following content to the &lt;code&gt;.npmrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a .npmrc file
touch .npmrc
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Add the following content to the .npmrc file
shamefully-hoist=true
engine-strict=true
save-exact = true
tag-version-prefix=&amp;quot;&amp;quot;
strict-peer-dependencies = false
auto-install-peers = true
lockfile = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After, we need to create a &lt;code&gt;.nvmrc&lt;/code&gt; file in the root directory of the Nextjs app, and we will add the following content to the &lt;code&gt;.nvmrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a .nvmrc file
touch .nvmrc
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Add the following content to the .nvmrc file
lts/fermium
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to create a &lt;code&gt;.yarnrc&lt;/code&gt; file in the root directory of the Nextjs app, and we will add the following content to the &lt;code&gt;.yarnrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a .yarnrc file
touch .yarnrc
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Add the following content to the .yarnrc file
--install.ignore-engines true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to create a &lt;code&gt;.prettierrc&lt;/code&gt; file in the root directory of the Nextjs app, and we will add the following content to the &lt;code&gt;.prettierrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a .prettierrc file
touch .prettierrc
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;# Add the following content to the .prettierrc file
{
  &amp;quot;printWidth&amp;quot;: 80,
  &amp;quot;tabWidth&amp;quot;: 2,
  &amp;quot;useTabs&amp;quot;: false,
  &amp;quot;semi&amp;quot;: true,
  &amp;quot;singleQuote&amp;quot;: true,
  &amp;quot;quoteProps&amp;quot;: &amp;quot;as-needed&amp;quot;,
  &amp;quot;jsxSingleQuote&amp;quot;: false,
  &amp;quot;trailingComma&amp;quot;: &amp;quot;es5&amp;quot;,
  &amp;quot;bracketSpacing&amp;quot;: true,
  &amp;quot;jsxBracketSameLine&amp;quot;: false,
  &amp;quot;arrowParens&amp;quot;: &amp;quot;always&amp;quot;,
  &amp;quot;requirePragma&amp;quot;: false,
  &amp;quot;insertPragma&amp;quot;: false,
  &amp;quot;proseWrap&amp;quot;: &amp;quot;preserve&amp;quot;,
  &amp;quot;htmlWhitespaceSensitivity&amp;quot;: &amp;quot;css&amp;quot;,
  &amp;quot;endOfLine&amp;quot;: &amp;quot;lf&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to create a &lt;code&gt;.prettierignore&lt;/code&gt; file in the root directory of the Nextjs app, and we will add the following content to the &lt;code&gt;.prettierignore&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a .prettierignore file
touch .prettierignore
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Add the following content to the .prettierignore file
.yarn
.vscode
.next
dist
node_modules
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to create a &lt;code&gt;.eslintrc&lt;/code&gt; file in the root directory of the Nextjs app, and we will add the following content to the &lt;code&gt;.eslintrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a .eslintrc file
touch .eslintrc
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;# Add the following content to the .eslintrc file
{
  &amp;quot;extends&amp;quot;: [&amp;quot;next&amp;quot;, &amp;quot;next/core-web-vitals&amp;quot;, &amp;quot;plugin:prettier/recommended&amp;quot;],
  &amp;quot;rules&amp;quot;: {
    &amp;quot;prettier/prettier&amp;quot;: [&amp;quot;error&amp;quot;, {}, { &amp;quot;usePrettierrc&amp;quot;: true }]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to create a &lt;code&gt;.eslintignore&lt;/code&gt; file in the root directory of the Nextjs app, and we will add the following content to the &lt;code&gt;.eslintignore&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a .eslintignore file
touch .eslintignore
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Add the following content to the .eslintignore file
.yarn
.vscode
.next
dist
node_modules
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add, the engines field to the &lt;code&gt;package.json&lt;/code&gt; file, and we will add the following content to the &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;# Add the following content to the package.json file
{
  &amp;quot;engines&amp;quot;: {
    &amp;quot;node&amp;quot;: &amp;quot;&amp;gt;=16.0.0&amp;quot;,
    &amp;quot;yarn&amp;quot;: &amp;quot;&amp;gt;=1.22.0&amp;quot;,
    &amp;quot;npm&amp;quot;: &amp;quot;please-use-yarn&amp;quot;
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Install Tailwind CSS&lt;/h3&gt;
&lt;p&gt;First, we will install Tailwind CSS using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install Tailwind CSS
yarn add -D tailwindcss@latest postcss@latest autoprefixer@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we will create a Tailwind CSS configuration file using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a Tailwind CSS configuration file
npx tailwindcss init -p
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After, we will change the &lt;code&gt;tailwind.config.js&lt;/code&gt; file, and we will add the following content to the &lt;code&gt;tailwind.config.js&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// Add the following content to the tailwind.config.js file
/** @type {import(&amp;#39;tailwindcss&amp;#39;).Config} */

module.exports = {
  content: [&amp;#39;./src/**/*.{js,ts,jsx,tsx}&amp;#39;],
  theme: {
    extend: {},
  },
  plugins: [],
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 5: Install Styled Components&lt;/h3&gt;
&lt;p&gt;First, we will install Styled Components using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install Styled Components
yarn add styled-components

# Install Styled Components TypeScript
yarn add -D @types/styled-components

# Install Styled Components Babel Plugin
yarn add -D babel-plugin-styled-components
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we will create a &lt;code&gt;.babelrc&lt;/code&gt; file in the root directory of the Nextjs app using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a .babelrc file
touch .babelrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we will add the following code to the &lt;code&gt;.babelrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;presets&amp;quot;: [&amp;quot;next/babel&amp;quot;],
  &amp;quot;plugins&amp;quot;: [
    [
      &amp;quot;styled-components&amp;quot;,
      {
        &amp;quot;ssr&amp;quot;: true,
        &amp;quot;displayName&amp;quot;: true,
        &amp;quot;preprocess&amp;quot;: false
      }
    ]
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 6: Install and Setup &lt;code&gt;twin.macro&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;First, we will install &lt;code&gt;twin.macro&lt;/code&gt; using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install twin.macro
yarn add twin.macro

# Install twin.macro Babel Plugin
yarn add -D babel-plugin-twin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we will add the following code to the &lt;code&gt;.babelrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;presets&amp;quot;: [&amp;quot;next/babel&amp;quot;],
  &amp;quot;plugins&amp;quot;: [
    [
      &amp;quot;styled-components&amp;quot;,
      {
        &amp;quot;ssr&amp;quot;: true,
        &amp;quot;displayName&amp;quot;: true,
        &amp;quot;preprocess&amp;quot;: false
      }
    ],
    [
      &amp;quot;babel-plugin-twin&amp;quot;,
      {
        &amp;quot;debug&amp;quot;: false,
        &amp;quot;styled&amp;quot;: &amp;quot;styled-components&amp;quot;
      }
    ],
    &amp;quot;babel-plugin-macros&amp;quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add, the &lt;code&gt;babelMacros&lt;/code&gt; field to the &lt;code&gt;package.json&lt;/code&gt; file, and we will add the following content to the &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;# Add the following content to the package.json file
{
  &amp;quot;babelMacros&amp;quot;: {
    &amp;quot;twin&amp;quot;: {
      &amp;quot;styled&amp;quot;: {
        &amp;quot;import&amp;quot;: &amp;quot;default&amp;quot;,
        &amp;quot;from&amp;quot;: &amp;quot;styled-components&amp;quot;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 7: Setup &lt;code&gt;_document.tsx&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;First, we will create a &lt;code&gt;pages/_document.tsx&lt;/code&gt; file using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a pages/_document.tsx file
touch pages/_document.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we will add the following code to the &lt;code&gt;pages/_document.tsx&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import Document, {
  DocumentContext,
  Head,
  Html,
  Main,
  NextScript,
} from &amp;#39;next/document&amp;#39;;
import {ServerStyleSheet} from &amp;#39;styled-components&amp;#39;;

export default class _Document extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =&amp;gt;
        originalRenderPage({
          enhanceApp: (App) =&amp;gt; (props) =&amp;gt;
            sheet.collectStyles(&amp;lt;App {...props} /&amp;gt;),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          &amp;lt;&amp;gt;
            {initialProps.styles}
            {sheet.getStyleElement()}
          &amp;lt;/&amp;gt;
        ),
      };
    } finally {
      sheet.seal();
    }
  }

  render() {
    return (
      &amp;lt;Html&amp;gt;
        &amp;lt;Head&amp;gt;
          &amp;lt;meta name=&amp;quot;theme-color&amp;quot; content=&amp;quot;#000000&amp;quot; /&amp;gt;
        &amp;lt;/Head&amp;gt;
        &amp;lt;body&amp;gt;
          &amp;lt;Main /&amp;gt;
          &amp;lt;NextScript /&amp;gt;
        &amp;lt;/body&amp;gt;
      &amp;lt;/Html&amp;gt;
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 8: Setup &lt;code&gt;_app.tsx&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;We will add the following code to the &lt;code&gt;pages/_app.tsx&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import type {AppProps} from &amp;#39;next/app&amp;#39;;
import Head from &amp;#39;next/head&amp;#39;;
import &amp;#39;tailwindcss/tailwind.css&amp;#39;;

const _App = ({Component, pageProps}: AppProps) =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Head&amp;gt;
        &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1&amp;quot; /&amp;gt;
        &amp;lt;title&amp;gt;Create Next App&amp;lt;/title&amp;gt;
        &amp;lt;meta name=&amp;quot;description&amp;quot; content=&amp;quot;Generated by create next app&amp;quot; /&amp;gt;
        &amp;lt;link rel=&amp;quot;icon&amp;quot; href=&amp;quot;/favicon.ico&amp;quot; /&amp;gt;
      &amp;lt;/Head&amp;gt;
      &amp;lt;Component {...pageProps} /&amp;gt;;
    &amp;lt;/&amp;gt;
  );
};

export default _App;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 9: Start styling&lt;/h3&gt;
&lt;p&gt;We will create a &lt;code&gt;styles&lt;/code&gt; directory in the root directory of the Nextjs app using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a styles directory
mkdir styles
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we will create a &lt;code&gt;main.ts&lt;/code&gt; file in the &lt;code&gt;styles&lt;/code&gt; directory using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a styles/main.ts file
touch styles/main.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we will add the following code to the &lt;code&gt;styles/main.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import styled from &amp;#39;styled-components&amp;#39;;
import tw from &amp;#39;twin.macro&amp;#39;;

export const Container = tw.div`
  flex
  min-h-screen
  flex-col
  items-center
  justify-center
  py-2
`;

export const Main = tw.main`
  flex
  w-full
  flex-1
  flex-col
  items-center
  justify-center
  px-20
  text-center
`;

export const Title = tw.h1`
  text-6xl
  font-bold
`;

export const TitleLink = tw.a`
  text-blue-600
`;

export const Description = tw.p`
  mt-3
  text-2xl
`;

export const DescriptionCodeHighlight = tw.code`
  rounded-md
  bg-gray-100
  p-3
  font-mono
  text-lg
`;

export const Cards = tw.div`
  mt-6 flex
  max-w-4xl
  flex-wrap
  items-center
  justify-around
  sm:w-full
`;

export const Card = tw.a`
  mt-6
  w-96
  rounded-xl
  border
  p-6
  text-left
  hover:text-blue-600
  focus:text-blue-600
`;

export const CardTitle = tw.h3`
  text-2xl
  font-bold
`;

export const CardDescription = tw.p`
  mt-4
  text-xl
`;

export const Footer = tw.footer`
  flex
  h-24
  w-full
  items-center
  justify-center
  border-t
`;

export const FooterCopyRight = tw.a`
  flex
  items-center
  justify-center
  gap-2
`;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we will redisign the &lt;code&gt;pages/index.tsx&lt;/code&gt; file using the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import {
  Container,
  Main,
  Title,
  TitleLink,
  Description,
  DescriptionCodeHighlight,
  Cards,
  Card,
  CardTitle,
  Footer,
  FooterCopyRight,
} from &amp;#39;../styles/Home.styles&amp;#39;;
import type {NextPage} from &amp;#39;next&amp;#39;;
import Image from &amp;#39;next/image&amp;#39;;

const HomePage: NextPage = () =&amp;gt; {
  return (
    &amp;lt;Container&amp;gt;
      &amp;lt;Main&amp;gt;
        &amp;lt;Title&amp;gt;
          Welcome to &amp;lt;TitleLink href=&amp;quot;https://nextjs.org&amp;quot;&amp;gt;Next.js!&amp;lt;/TitleLink&amp;gt;
        &amp;lt;/Title&amp;gt;

        &amp;lt;Description&amp;gt;
          Get started by editing{&amp;#39; &amp;#39;}
          &amp;lt;DescriptionCodeHighlight&amp;gt;pages/index.tsx&amp;lt;/DescriptionCodeHighlight&amp;gt;
        &amp;lt;/Description&amp;gt;

        &amp;lt;Cards&amp;gt;
          &amp;lt;Card href=&amp;quot;https://nextjs.org/docs&amp;quot;&amp;gt;
            &amp;lt;CardTitle&amp;gt;Documentation &amp;amp;rarr;&amp;lt;/CardTitle&amp;gt;
            &amp;lt;p&amp;gt;Find in-depth information about Next.js features and API.&amp;lt;/p&amp;gt;
          &amp;lt;/Card&amp;gt;

          &amp;lt;Card href=&amp;quot;https://nextjs.org/learn&amp;quot;&amp;gt;
            &amp;lt;CardTitle&amp;gt;Learn &amp;amp;rarr;&amp;lt;/CardTitle&amp;gt;
            &amp;lt;p&amp;gt;Learn about Next.js in an interactive course with quizzes!&amp;lt;/p&amp;gt;
          &amp;lt;/Card&amp;gt;

          &amp;lt;Card href=&amp;quot;https://github.com/vercel/next.js/tree/canary/examples&amp;quot;&amp;gt;
            &amp;lt;CardTitle&amp;gt;Examples &amp;amp;rarr;&amp;lt;/CardTitle&amp;gt;
            &amp;lt;p&amp;gt;Discover and deploy boilerplate example Next.js projects.&amp;lt;/p&amp;gt;
          &amp;lt;/Card&amp;gt;

          &amp;lt;Card
            href=&amp;quot;https://vercel.com/new?utm_source=create-next-app&amp;amp;utm_medium=default-template&amp;amp;utm_campaign=create-next-app&amp;quot;
            target=&amp;quot;_blank&amp;quot;
            rel=&amp;quot;noopener noreferrer&amp;quot;
          &amp;gt;
            &amp;lt;h2&amp;gt;Deploy &amp;amp;rarr;&amp;lt;/h2&amp;gt;
            &amp;lt;p&amp;gt;
              Instantly deploy your Next.js site to a public URL with Vercel.
            &amp;lt;/p&amp;gt;
          &amp;lt;/Card&amp;gt;
        &amp;lt;/Cards&amp;gt;
      &amp;lt;/Main&amp;gt;

      &amp;lt;Footer&amp;gt;
        &amp;lt;FooterCopyRight
          href=&amp;quot;https://vercel.com?utm_source=create-next-app&amp;amp;utm_medium=default-template&amp;amp;utm_campaign=create-next-app&amp;quot;
          target=&amp;quot;_blank&amp;quot;
          rel=&amp;quot;noopener noreferrer&amp;quot;
        &amp;gt;
          Powered by{&amp;#39; &amp;#39;}
          &amp;lt;Image src=&amp;quot;/vercel.svg&amp;quot; alt=&amp;quot;Vercel Logo&amp;quot; width={72} height={16} /&amp;gt;
        &amp;lt;/FooterCopyRight&amp;gt;
      &amp;lt;/Footer&amp;gt;
    &amp;lt;/Container&amp;gt;
  );
};

export default HomePage;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Source Code&lt;/h2&gt;
&lt;p&gt;The source code for this tutorial is available on &lt;a href=&quot;https://github.com/MKAbuMattar/nextjs-tailwind-styled-components-typescript&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Live Demo&lt;/h2&gt;
&lt;p&gt;The live demo for this tutorial is available on &lt;a href=&quot;https://nextjs-tailwind-styled-components-typescript.vercel.app/&quot;&gt;Vercel&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we have learned how to use Tailwind CSS with Nextjs and Styled Components. We have also learned how to use TypeScript with Nextjs and Styled Components.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/docs&quot;&gt;Next.js Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/docs&quot;&gt;Tailwind CSS Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://styled-components.com/docs&quot;&gt;Styled Components Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/&quot;&gt;TypeScript Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ben-rogerson/twin.macro&quot;&gt;twin.macro GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/typescript&quot;&gt;Next.js with TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/docs/guides/nextjs&quot;&gt;Install Tailwind CSS with Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://styled-components.com/docs/advanced#nextjs&quot;&gt;Styled Components: Advanced Usage - Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/&quot;&gt;Prettier Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yarnpkg.com/&quot;&gt;Yarn Package Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel Platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/MKAbuMattar/nextjs-tailwind-styled-components-typescript&quot;&gt;Source Code for this tutorial on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Next.js</category><category>Tailwind CSS</category><category>Styled Components</category><category>TypeScript</category><category>Frontend Development</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0020-setup-nextjs-tailwind-css-styled-components-with-typescript/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Connect to AWS RDS MySQL Database to EC2 Instance With PHP By Using PDO</title><link>https://mkabumattar.com/blog/post/how-to-connect-to-aws-rds-mysql-database-to-ec2-instance-with-php-by-using-pdo/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-connect-to-aws-rds-mysql-database-to-ec2-instance-with-php-by-using-pdo/</guid><description>In this post, we will learn how to connect to AWS RDS MySQL Database to EC2 Instance With PHP By Using PDO.</description><pubDate>Mon, 07 Nov 2022 21:27:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, we will learn how to connect to AWS RDS MySQL Database to EC2 Instance With PHP By Using PDO.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;EC2 Instance Amazon Linux 2&lt;/li&gt;
&lt;li&gt;RDS MySQL Database&lt;/li&gt;
&lt;li&gt;MySQL Workbench&lt;/li&gt;
&lt;li&gt;SSH Client&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;
  In previous posts, we have learned how to create a AWS RDS MySQL Database and
  connect to it using MySQL Workbench. If you have not read the previous posts,
  you can read them from the following links: [How to Create a AWS RDS MySQL
  Database and Connect to it Using MySQL
  Workbench](/blog/post/how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench)
&lt;/Notice&gt;&lt;hr&gt;
&lt;Notice type=&quot;note&quot;&gt;
  In previous posts, we have learned how to create a AWS EC2 Instance Amazon
  Linux 2. If you have not read the previous posts, you can read them from the
  following links: [How To Create An AWS EC2 Instance Using AWS
  CLI](/blog/post/how-to-create-an-aws-ec2-instance-using-aws-cli)
&lt;/Notice&gt;&lt;h2&gt;Create a PHP File structure&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/www/html
├── connect.php
├── insert.php
├── index.php
└── insert-boats-form.php
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Connect RDS MySQL Database to EC2 Instance With PHP By Using PDO&lt;/h2&gt;
&lt;h3&gt;Create a connect.php file&lt;/h3&gt;
&lt;p&gt;We will create a &lt;code&gt;connect.php&lt;/code&gt; file in the &lt;code&gt;/var/www/html&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
    $servername = &amp;quot;localhost&amp;quot;;
    $username = &amp;quot;root&amp;quot;;
    $password = &amp;quot;password&amp;quot;;
    $dbname = &amp;quot;SAI&amp;quot;;
    $port = &amp;quot;3306&amp;quot;;

    $dsn = &amp;quot;mysql:host=$servername;port=$port;dbname=$dbname&amp;quot;;

    try {
        $conn = new PDO($dsn, $username, $password);
        $conn-&amp;gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        echo &amp;quot;Connected successfully&amp;quot;;
    } catch(PDOException $e) {
        echo &amp;quot;Connection failed: &amp;quot; . $e-&amp;gt;getMessage();
    }

?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$servername&lt;/code&gt; - The server name of the RDS MySQL Database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$username&lt;/code&gt; - The username of the RDS MySQL Database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$password&lt;/code&gt; - The password of the RDS MySQL Database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$dbname&lt;/code&gt; - The database name of the RDS MySQL Database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$port&lt;/code&gt; - The port of the RDS MySQL Database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$dsn&lt;/code&gt; - The Data Source Name, or DSN, contains the information required to connect to the database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$conn&lt;/code&gt; - The connection object.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PDO::ATTR_ERRMODE&lt;/code&gt; - The error reporting attribute.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PDO::ERRMODE_EXCEPTION&lt;/code&gt; - Throw exceptions for errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;h3&gt;Create a insert.php file&lt;/h3&gt;
&lt;p&gt;We will create a &lt;code&gt;insert.php&lt;/code&gt; file in the &lt;code&gt;/var/www/html&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
    try {
        include_once &amp;#39;connect.php&amp;#39;;

        $bid = $_POST[&amp;#39;bid&amp;#39;];
        $bname = $_POST[&amp;#39;bname&amp;#39;];
        $color = $_POST[&amp;#39;color&amp;#39;];

        $search = $conn-&amp;gt;prepare(
            &amp;quot;INSERT INTO BOATS (BID, BName, BColor) VALUES (:bid, :bname, :color)&amp;quot;
        );

        $search-&amp;gt;bindParam(&amp;#39;:bid&amp;#39;, $bid);
        $search-&amp;gt;bindParam(&amp;#39;:bname&amp;#39;, $bname);
        $search-&amp;gt;bindParam(&amp;#39;:color&amp;#39;, $color);

        $search-&amp;gt;execute();

        $conn = null;
    } catch(PDOException $e) {
        echo &amp;quot;Connection failed: &amp;quot; . $e-&amp;gt;getMessage();
        $conn = null;
    }
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;include_once &amp;#39;../config/connect.php&amp;#39;&lt;/code&gt; - Include the &lt;code&gt;connect.php&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$_POST[&amp;#39;bid&amp;#39;]&lt;/code&gt; - Get the &lt;code&gt;bid&lt;/code&gt; value from the &lt;code&gt;POST&lt;/code&gt; request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$_POST[&amp;#39;bname&amp;#39;]&lt;/code&gt; - Get the &lt;code&gt;bname&lt;/code&gt; value from the &lt;code&gt;POST&lt;/code&gt; request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$_POST[&amp;#39;color&amp;#39;]&lt;/code&gt; - Get the &lt;code&gt;color&lt;/code&gt; value from the &lt;code&gt;POST&lt;/code&gt; request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$search = $conn-&amp;gt;prepare()&lt;/code&gt; - Prepare the SQL statement.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$search-&amp;gt;bindParam(&amp;#39;:bid&amp;#39;, $bid)&lt;/code&gt; - Bind the &lt;code&gt;bid&lt;/code&gt; value to the &lt;code&gt;:bid&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$search-&amp;gt;bindParam(&amp;#39;:bname&amp;#39;, $bname)&lt;/code&gt; - Bind the &lt;code&gt;bname&lt;/code&gt; value to the &lt;code&gt;:bname&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$search-&amp;gt;bindParam(&amp;#39;:color&amp;#39;, $color)&lt;/code&gt; - Bind the &lt;code&gt;color&lt;/code&gt; value to the &lt;code&gt;:color&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$search-&amp;gt;execute()&lt;/code&gt; - Execute the SQL statement.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$conn = null&lt;/code&gt; - Close the connection.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;echo &amp;quot;Connection failed: &amp;quot; . $e-&amp;gt;getMessage()&lt;/code&gt; - Print the error message.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;h3&gt;Create a index.php file&lt;/h3&gt;
&lt;p&gt;We will create a &lt;code&gt;index.php&lt;/code&gt; file in the &lt;code&gt;/var/www/html&lt;/code&gt; directory. We will conneact to DB using &lt;code&gt;connect.php&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
    include_once &amp;#39;connect.php&amp;#39;;

    $query_SAILORS = &amp;quot;SELECT * FROM SAILORS&amp;quot;;
    $query_BOATS = &amp;quot;SELECT * FROM BOATS&amp;quot;;
    $query_RESERVES = &amp;quot;SELECT * FROM RESERVES&amp;quot;;
    $query_1 = &amp;quot;SELECT * FROM SAILORS WHERE SID in (select SID from RESERVES WHERE BID = 101)&amp;quot;;
    $query_2 = &amp;quot;SELECT SName FROM SAILORS WHERE SID in (select SID from RESERVES WHERE BID in (select BID from BOATS WHERE BColor = &amp;#39;red&amp;#39;)) order by SAge&amp;quot;;
    $query_3 = &amp;quot;SELECT SName FROM SAILORS WHERE SID in (select SID from RESERVES)&amp;quot;;
    $query_4 = &amp;quot;SELECT SID, SName FROM SAILORS WHERE SID in (select SID from RESERVES group by SID, Day having count(*) &amp;gt;= 2)&amp;quot;;
    $query_5 = &amp;quot;SELECT SID FROM SAILORS WHERE SID in (select SID from RESERVES WHERE BID in (select BID from BOATS WHERE BColor = &amp;#39;red&amp;#39;)) or SID in (select SID from RESERVES WHERE BID in (select BID from BOATS WHERE BColor = &amp;#39;green&amp;#39;))&amp;quot;;

    $result_SAILORS = $conn-&amp;gt;query($query_SAILORS);
    $result_BOATS = $conn-&amp;gt;query($query_BOATS);
    $result_RESERVES = $conn-&amp;gt;query($query_RESERVES);
    $result_1 = $conn-&amp;gt;query($query_1);
    $result_2 = $conn-&amp;gt;query($query_2);
    $result_3 = $conn-&amp;gt;query($query_3);
    $result_4 = $conn-&amp;gt;query($query_4);
    $result_5 = $conn-&amp;gt;query($query_5);

    $SAILORS = $result_SAILORS-&amp;gt;fetchAll();
    $BOATS = $result_BOATS-&amp;gt;fetchAll();
    $RESERVES = $result_RESERVES-&amp;gt;fetchAll();
    $result_1 = $result_1-&amp;gt;fetchAll();
    $result_2 = $result_2-&amp;gt;fetchAll();
    $result_3 = $result_3-&amp;gt;fetchAll();
    $result_4 = $result_4-&amp;gt;fetchAll();
    $result_5 = $result_5-&amp;gt;fetchAll();

  $conn = null;
?&amp;gt;

&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;SAI&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.4.6/tailwind.min.css&amp;quot;&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div class=&amp;quot;container mx-auto&amp;quot;&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h1 class=&amp;quot;text-4xl text-center&amp;quot;&amp;gt;SAI&amp;lt;/h1&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h2 class=&amp;quot;text-2xl text-center&amp;quot;&amp;gt;SAILORS&amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;table class=&amp;quot;table-auto&amp;quot;&amp;gt;
                    &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SID&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SName&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SRating&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SAge&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/thead&amp;gt;
                    &amp;lt;tbody&amp;gt;
                        &amp;lt;?php foreach ($SAILORS as $SAILOR): ?&amp;gt;
                            &amp;lt;tr&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $SAILOR[&amp;#39;SID&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $SAILOR[&amp;#39;SName&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $SAILOR[&amp;#39;SRating&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $SAILOR[&amp;#39;SAge&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                            &amp;lt;/tr&amp;gt;
                        &amp;lt;?php endforeach; ?&amp;gt;
                    &amp;lt;/tbody&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h2 class=&amp;quot;text-2xl text-center&amp;quot;&amp;gt;BOATS&amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;table class=&amp;quot;table-auto&amp;quot;&amp;gt;
                    &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;BID&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;BName&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;BColor&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/thead&amp;gt;
                    &amp;lt;tbody&amp;gt;
                        &amp;lt;?php foreach ($BOATS as $BOAT): ?&amp;gt;
                            &amp;lt;tr&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $BOAT[&amp;#39;BID&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $BOAT[&amp;#39;BName&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $BOAT[&amp;#39;BColor&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                            &amp;lt;/tr&amp;gt;
                        &amp;lt;?php endforeach; ?&amp;gt;
                    &amp;lt;/tbody&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h2 class=&amp;quot;text-2xl text-center&amp;quot;&amp;gt;RESERVES&amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;table class=&amp;quot;table-auto&amp;quot;&amp;gt;
                    &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SID&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;BID&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;Day&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/thead&amp;gt;
                    &amp;lt;tbody&amp;gt;
                        &amp;lt;?php foreach ($RESERVES as $RESERVE): ?&amp;gt;
                            &amp;lt;tr&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $RESERVE[&amp;#39;SID&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $RESERVE[&amp;#39;BID&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $RESERVE[&amp;#39;Day&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                            &amp;lt;/tr&amp;gt;
                        &amp;lt;?php endforeach; ?&amp;gt;
                    &amp;lt;/tbody&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h2 class=&amp;quot;text-2xl text-center&amp;quot;&amp;gt;Find all information of sailors who have reserved boat number 101.&amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;table class=&amp;quot;table-auto&amp;quot;&amp;gt;
                    &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SID&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SName&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SRating&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SAge&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/thead&amp;gt;
                    &amp;lt;tbody&amp;gt;
                        &amp;lt;?php foreach ($result_1 as $row): ?&amp;gt;
                            &amp;lt;tr&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $row[&amp;#39;SID&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $row[&amp;#39;SName&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $row[&amp;#39;SRating&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $row[&amp;#39;SAge&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                            &amp;lt;/tr&amp;gt;
                        &amp;lt;?php endforeach; ?&amp;gt;
                    &amp;lt;/tbody&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h2 class=&amp;quot;text-2xl text-center&amp;quot;&amp;gt;Find the names of sailors who have reserved a red boat, and list in the order of age.&amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;table class=&amp;quot;table-auto&amp;quot;&amp;gt;
                    &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SName&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/thead&amp;gt;
                    &amp;lt;tbody&amp;gt;
                        &amp;lt;?php foreach ($result_2 as $row): ?&amp;gt;
                            &amp;lt;tr&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $row[&amp;#39;SName&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                            &amp;lt;/tr&amp;gt;
                        &amp;lt;?php endforeach; ?&amp;gt;
                    &amp;lt;/tbody&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h2 class=&amp;quot;text-2xl text-center&amp;quot;&amp;gt;Find the names of sailors who have reserved at least one boat. &amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;table class=&amp;quot;table-auto&amp;quot;&amp;gt;
                    &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SName&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/thead&amp;gt;
                    &amp;lt;tbody&amp;gt;
                        &amp;lt;?php foreach ($result_3 as $row): ?&amp;gt;
                            &amp;lt;tr&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $row[&amp;#39;SName&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                            &amp;lt;/tr&amp;gt;
                        &amp;lt;?php endforeach; ?&amp;gt;
                    &amp;lt;/tbody&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h2 class=&amp;quot;text-2xl text-center&amp;quot;&amp;gt;Find the ids and names of sailors who have reserved two different boats on the same day.&amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;table class=&amp;quot;table-auto&amp;quot;&amp;gt;
                    &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SID&amp;lt;/th&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SName&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/thead&amp;gt;
                    &amp;lt;tbody&amp;gt;
                        &amp;lt;?php foreach ($result_4 as $row): ?&amp;gt;
                            &amp;lt;tr&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $row[&amp;#39;SID&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $row[&amp;#39;SName&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                            &amp;lt;/tr&amp;gt;
                        &amp;lt;?php endforeach; ?&amp;gt;
                    &amp;lt;/tbody&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h2 class=&amp;quot;text-2xl text-center&amp;quot;&amp;gt;Find the ids of sailors who have reserved a red boat or a green boat.&amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;table class=&amp;quot;table-auto&amp;quot;&amp;gt;
                    &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th class=&amp;quot;px-4 py-2&amp;quot;&amp;gt;SID&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/thead&amp;gt;
                    &amp;lt;tbody&amp;gt;
                        &amp;lt;?php foreach ($result_5 as $row): ?&amp;gt;
                            &amp;lt;tr&amp;gt;
                                &amp;lt;td class=&amp;quot;border px-4 py-2&amp;quot;&amp;gt;&amp;lt;?php echo $row[&amp;#39;SID&amp;#39;] ?&amp;gt;&amp;lt;/td&amp;gt;
                            &amp;lt;/tr&amp;gt;
                        &amp;lt;?php endforeach; ?&amp;gt;
                    &amp;lt;/tbody&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;Select all columns from the &lt;code&gt;SAILORS&lt;/code&gt; table&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM SAILORS
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Select all columns from the &lt;code&gt;BOATS&lt;/code&gt; table&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM BOATS
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Select all columns from the &lt;code&gt;RESERVES&lt;/code&gt; table&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM RESERVES
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Select all columns from the &lt;code&gt;SAILORS&lt;/code&gt; table where the &lt;code&gt;SID&lt;/code&gt; is in the &lt;code&gt;SID&lt;/code&gt; column of the &lt;code&gt;RESERVES&lt;/code&gt; table where the &lt;code&gt;BID&lt;/code&gt; is equal to &lt;code&gt;101&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select * from `SAI`.`SAILORS`
WHERE SID in (
    select SID from `SAI`.`RESERVES`
    WHERE BID = 101
);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Select the &lt;code&gt;SName&lt;/code&gt; column from the &lt;code&gt;SAILORS&lt;/code&gt; table where the &lt;code&gt;SID&lt;/code&gt; is in the &lt;code&gt;SID&lt;/code&gt; column of the &lt;code&gt;RESERVES&lt;/code&gt; table where the &lt;code&gt;BID&lt;/code&gt; is in the &lt;code&gt;BID&lt;/code&gt; column of the &lt;code&gt;BOATS&lt;/code&gt; table where the &lt;code&gt;BColor&lt;/code&gt; is equal to &lt;code&gt;&amp;#39;red&amp;#39;&lt;/code&gt; and order the results by the &lt;code&gt;SAge&lt;/code&gt; column&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select SName from `SAI`.`SAILORS`
WHERE SID in (
    select SID from `SAI`.`RESERVES`
    WHERE BID in (
        select BID from `SAI`.`BOATS`
        WHERE BColor = &amp;#39;red&amp;#39;
    )
)
order by SAge;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Select the &lt;code&gt;SName&lt;/code&gt; column from the &lt;code&gt;SAILORS&lt;/code&gt; table where the &lt;code&gt;SID&lt;/code&gt; is in the &lt;code&gt;SID&lt;/code&gt; column of the &lt;code&gt;RESERVES&lt;/code&gt; table&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select SName from `SAI`.`SAILORS`
WHERE SID in (
    select SID from `SAI`.`RESERVES`
);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Select the &lt;code&gt;SID&lt;/code&gt; and &lt;code&gt;SName&lt;/code&gt; columns from the &lt;code&gt;SAILORS&lt;/code&gt; table where the &lt;code&gt;SID&lt;/code&gt; is in the &lt;code&gt;SID&lt;/code&gt; column of the &lt;code&gt;RESERVES&lt;/code&gt; table grouped by the &lt;code&gt;SID&lt;/code&gt; and &lt;code&gt;Day&lt;/code&gt; columns having a count of &lt;code&gt;*&lt;/code&gt; greater than or equal to &lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select SID, SName from `SAI`.`SAILORS`
WHERE SID in (
    select SID from `SAI`.`RESERVES`
    group by SID, Day
    having count(*) &amp;gt;= 2
);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Select the &lt;code&gt;SID&lt;/code&gt; column from the &lt;code&gt;SAILORS&lt;/code&gt; table where the &lt;code&gt;SID&lt;/code&gt; is in the &lt;code&gt;SID&lt;/code&gt; column of the &lt;code&gt;RESERVES&lt;/code&gt; table where the &lt;code&gt;BID&lt;/code&gt; is in the &lt;code&gt;BID&lt;/code&gt; column of the &lt;code&gt;BOATS&lt;/code&gt; table where the &lt;code&gt;BColor&lt;/code&gt; is equal to &lt;code&gt;&amp;#39;red&amp;#39;&lt;/code&gt; or the &lt;code&gt;SID&lt;/code&gt; is in the &lt;code&gt;SID&lt;/code&gt; column of the &lt;code&gt;RESERVES&lt;/code&gt; table where the &lt;code&gt;BID&lt;/code&gt; is in the &lt;code&gt;BID&lt;/code&gt; column of the &lt;code&gt;BOATS&lt;/code&gt; table where the &lt;code&gt;BColor&lt;/code&gt; is equal to &lt;code&gt;&amp;#39;green&amp;#39;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select SID from `SAI`.`SAILORS`
WHERE SID in (
    select SID from `SAI`.`RESERVES`
    WHERE BID in (
        select BID from `SAI`.`BOATS`
        WHERE BColor = &amp;#39;red&amp;#39;
    )
)
or SID in (
    select SID from `SAI`.`RESERVES`
    WHERE BID in (
        select BID from `SAI`.`BOATS`
        WHERE BColor = &amp;#39;green&amp;#39;
    )
);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$result =$conn-&amp;gt;query($query)&lt;/code&gt; executes the query and returns the result as a &lt;code&gt;mysqlPDOStatement&lt;/code&gt; object which can be used to fetch the results as an associative array using the &lt;code&gt;fetchAll()&lt;/code&gt; method&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$result-&amp;gt;fetchAll();&lt;/code&gt; fetches all the results as an associative array and returns it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;?php foreach ($results as $row): ?&amp;gt;&lt;/code&gt; loops through the results and assigns each row to the &lt;code&gt;$row&lt;/code&gt; variable&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;?php echo $row[&amp;#39;column_name&amp;#39;] ?&amp;gt;&lt;/code&gt; prints the value of the column with the name &lt;code&gt;column_name&lt;/code&gt; in the current row&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;?php endforeach; ?&amp;gt;&lt;/code&gt; ends the loop&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;h2&gt;Create a form to insert a new row into the &lt;code&gt;BOATS&lt;/code&gt; table&lt;/h2&gt;
&lt;p&gt;We will create a new file &lt;code&gt;insert-boats-form.php&lt;/code&gt; in the &lt;code&gt;/var/www/html&lt;/code&gt; directory and add the following code to it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;SAI&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.4.6/tailwind.min.css&amp;quot;&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div class=&amp;quot;container mx-auto&amp;quot;&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h1 class=&amp;quot;text-4xl text-center&amp;quot;&amp;gt;SAI&amp;lt;/h1&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;h2 class=&amp;quot;text-2xl text-center&amp;quot;&amp;gt;Insert data into database&amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
            &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                &amp;lt;form action=&amp;quot;insert.boats.php&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;
                    &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
                        &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                            &amp;lt;label class=&amp;quot;block text-gray-700 text-sm font-bold mb-2&amp;quot; for=&amp;quot;bid&amp;quot;&amp;gt;
                                bid
                            &amp;lt;/label&amp;gt;
                            &amp;lt;input class=&amp;quot;shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline&amp;quot; id=&amp;quot;bid&amp;quot; name=&amp;quot;bid&amp;quot; type=&amp;quot;text&amp;quot; placeholder=&amp;quot;bid&amp;quot;&amp;gt;
                        &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
                        &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                            &amp;lt;label class=&amp;quot;block text-gray-700 text-sm font-bold mb-2&amp;quot; for=&amp;quot;bname&amp;quot;&amp;gt;
                                bname
                            &amp;lt;/label&amp;gt;
                            &amp;lt;input class=&amp;quot;shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline&amp;quot; id=&amp;quot;bname&amp;quot; name=&amp;quot;bname&amp;quot; type=&amp;quot;text&amp;quot; placeholder=&amp;quot;bname&amp;quot;&amp;gt;
                        &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
                        &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                            &amp;lt;label class=&amp;quot;block text-gray-700 text-sm font-bold mb-2&amp;quot; for=&amp;quot;color&amp;quot;&amp;gt;
                                color
                            &amp;lt;/label&amp;gt;
                            &amp;lt;input class=&amp;quot;shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline&amp;quot; id=&amp;quot;color&amp;quot; name=&amp;quot;color&amp;quot; type=&amp;quot;text&amp;quot; placeholder=&amp;quot;color&amp;quot;&amp;gt;
                        &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div class=&amp;quot;flex flex-wrap&amp;quot;&amp;gt;
                        &amp;lt;div class=&amp;quot;w-full&amp;quot;&amp;gt;
                            &amp;lt;button class=&amp;quot;bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline w-full&amp;quot; type=&amp;quot;submit&amp;quot;&amp;gt;
                                Submit
                            &amp;lt;/button&amp;gt;
                        &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                &amp;lt;/form&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;action&lt;/code&gt; attribute of the form is set to &lt;code&gt;insert-boats.php&lt;/code&gt; which is the file that will handle the form submission&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;method&lt;/code&gt; attribute of the form is set to &lt;code&gt;post&lt;/code&gt; which means that the form data will be sent to the server using the &lt;code&gt;POST&lt;/code&gt; method&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;id&lt;/code&gt; attribute of the input elements are set to the column names of the &lt;code&gt;BOATS&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;name&lt;/code&gt; attribute of the input elements are set to the column names of the &lt;code&gt;BOATS&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;type&lt;/code&gt; attribute of the input elements are set to &lt;code&gt;text&lt;/code&gt; which means that the input will be a text input&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;placeholder&lt;/code&gt; attribute of the input elements are set to the column names of the &lt;code&gt;BOATS&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;type&lt;/code&gt; attribute of the submit button is set to &lt;code&gt;submit&lt;/code&gt; which means that the button will submit the form&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, How to connect to a MySQL database using PHP was explained. We also learned how to create a form to insert data into a MySQL database using PHP.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/pdo.construct.php&quot;&gt;PHP Manual - PDO::__construct&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/pdo.prepare.php&quot;&gt;PHP Manual - PDO::prepare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/pdostatement.bindparam.php&quot;&gt;PHP Manual - PDOStatement::bindParam&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/pdostatement.execute.php&quot;&gt;PHP Manual - PDOStatement::execute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/pdostatement.fetchall.php&quot;&gt;PHP Manual - PDOStatement::fetchAll&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/pdo.setattribute.php&quot;&gt;PHP Manual - PDO::setAttribute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html&quot;&gt;Amazon RDS User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ConnectToInstance.html&quot;&gt;Connecting to an Amazon RDS DB instance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html&quot;&gt;Tutorial: Installing a LAMP Web Server on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html&quot;&gt;Connecting to your Linux instance using SSH&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html&quot;&gt;Security groups for your VPC&lt;/a&gt; (Relevant for RDS and EC2 access)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/&quot;&gt;MySQL Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/docs&quot;&gt;Tailwind CSS Documentation (for styling the example)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>RDS</category><category>EC2</category><category>PHP</category><category>MySQL</category><category>Database</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0019-how-to-connect-to-aws-rds-mysql-database-to-ec2-instance-with-php-by-using-pdo/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Install and Configure Node.js on EC2 Instance Amazon Linux 2</title><link>https://mkabumattar.com/blog/post/how-to-install-and-configure-nodejs-on-ec2-instance-amazon-linux-2/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-install-and-configure-nodejs-on-ec2-instance-amazon-linux-2/</guid><description>Node.js does not exist in the default Amazon Linux 2 repository. So, we need to add the Node.js repository to the system. In this post, we will learn how to install and configure Node.js on EC2 Instance Amazon Linux 2.</description><pubDate>Mon, 07 Nov 2022 03:18:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Node.js does not exist in the default Amazon Linux 2 repository. So, we need to add the Node.js repository to the system. In this post, we will learn how to install and configure Node.js on EC2 Instance Amazon Linux 2.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;EC2 Instance Amazon Linux 2&lt;/li&gt;
&lt;li&gt;SSH Client&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step 1: Update the System Packages and Install Dependencies Packages&lt;/h2&gt;
&lt;p&gt;First, we need to update the system packages and install dependencies packages.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Update the system packages
sudo yum update -y

# Install dependencies packages
sudo yum install gcc-c++ make -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Step 2: Install Node.js&lt;/h2&gt;
&lt;p&gt;First, we need to install Node.js on our EC2 Instance. To do that, we need to add the Node.js repository to the system. To add the Node.js repository, we need to run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install Node.js repository 14.x
curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash -

# Install Node.js repository 16.x
curl -sL https://rpm.nodesource.com/setup_16.x | sudo bash -

# Install Node.js repository 17.x
curl -sL https://rpm.nodesource.com/setup_17.x | sudo bash -

# Install Node.js repository 18.x
curl -sL https://rpm.nodesource.com/setup_18.x | sudo bash -
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Step 3: Install Node.js&lt;/h2&gt;
&lt;p&gt;After choosing the Node.js version, we need to install Node.js on our EC2 Instance. To do that, we need to run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# update the system
sudo yum update -y

# Install Node.js
sudo yum install nodejs -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Step 4: Check Node.js Version&lt;/h2&gt;
&lt;p&gt;After installing Node.js, we need to check the Node.js version. To do that, we need to run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;node -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output depends on the Node.js version that you choose.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Node.js 14.x
v14.18.1

# Node.js 16.x
v16.13.0

# Node.js 17.x
v17.0.1

# Node.js 18.x
v18.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post, we learned how to install and configure Node.js on EC2 Instance Amazon Linux 2. We learned how to add the Node.js repository to the system and install Node.js on our EC2 Instance.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodesource/distributions&quot;&gt;NodeSource Node.js Binary Distributions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora&quot;&gt;Installing Node.js via package manager - NodeSource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/amazon-linux-2/faqs/&quot;&gt;Amazon Linux 2 AMI FAQs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html&quot;&gt;Connect to your Linux instance using SSH&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/managing-software.html&quot;&gt;Managing software on your Linux instance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://access.redhat.com/sites/default/files/attachments/rh_yum_cheatsheet_1214_jcs_print-1.pdf&quot;&gt;Red Hat Enterprise Linux (RHEL) and CentOS &lt;code&gt;yum&lt;/code&gt; command cheat sheet&lt;/a&gt; (Amazon Linux is RHEL-based)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://curl.se/docs/manual.html&quot;&gt;cURL Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/bash.html&quot;&gt;Bash Manual&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>EC2</category><category>Node.js</category><category>Linux</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0018-how-to-install-and-configure-nodejs-on-ec2-instance-amazon-linux-2/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Create a AWS RDS MySQL Database and Connect to it using MySQL Workbench</title><link>https://mkabumattar.com/blog/post/how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/</guid><description>RDS is a managed service that makes it easy to set up, operate, and scale a relational database in the cloud. It provides cost-efficient and resizable capacity while automating time-consuming administration tasks such as hardware provisioning, database setup, patching and backups. It frees you to focus on your applications so you can give them the fast performance, high availability, security, and compatibility they need.</description><pubDate>Mon, 07 Nov 2022 01:51:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;RDS is a managed service that makes it easy to set up, operate, and scale a relational database in the cloud. It provides cost-efficient and resizable capacity while automating time-consuming administration tasks such as hardware provisioning, database setup, patching and backups. It frees you to focus on your applications so you can give them the fast performance, high availability, security, and compatibility they need.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;MySQL Workbench&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create a AWS RDS MySQL Database&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Login to your AWS Console.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/aws-console.png&quot; alt=&quot;AWS Console&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Click on Services and then click on RDS.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/rds.png&quot; alt=&quot;RDS&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click on Create Database.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/create-database.png&quot; alt=&quot;Create Database&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Select MySQL as the database engine.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/select-mysql.png&quot; alt=&quot;Select MySQL&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Select the MySQL version.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/select-mysql-version.png&quot; alt=&quot;Select MySQL Version&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Select the template.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/select-template.png&quot; alt=&quot;Select Template&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;DB instance identifier.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/db-instance-identifier.png&quot; alt=&quot;DB Instance Identifier&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;Master username and password.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/master-username-and-password.png&quot; alt=&quot;Master Username and Password&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;DB instance class.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/db-instance-class.png&quot; alt=&quot;DB Instance Class&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;10&quot;&gt;
&lt;li&gt;Storage.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/storage.png&quot; alt=&quot;Storage&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;11&quot;&gt;
&lt;li&gt;Public access&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/public-acces.png&quot; alt=&quot;Public Access&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;12&quot;&gt;
&lt;li&gt;VPC security group.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/vpc-security-group.png&quot; alt=&quot;VPC Security Group&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;13&quot;&gt;
&lt;li&gt;Additional configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/additional-configuration.png&quot; alt=&quot;Additional Configuration&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;14&quot;&gt;
&lt;li&gt;Click on Create database.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Connect to the AWS RDS MySQL Database&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Get the endpoint of the database.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/get-endpoint.png&quot; alt=&quot;Get Endpoint&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Open MySQL Workbench.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/open-mysql-workbench.png&quot; alt=&quot;Open MySQL Workbench&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click on the + icon to add a new connection.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/add-new-connection.png&quot; alt=&quot;Add New Connection&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Enter the connection details.&lt;ul&gt;
&lt;li&gt;Connection Name: Enter a name for the connection.&lt;/li&gt;
&lt;li&gt;Hostname: Enter the endpoint of the database.&lt;/li&gt;
&lt;li&gt;Username: Enter the username of the database.&lt;/li&gt;
&lt;li&gt;Password: Enter the password of the database.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/enter-connection-details.png&quot; alt=&quot;Enter Connection Details&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;p&gt;Click on Test Connection to test the connection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on OK to save the connection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the connection to connect to the database.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You have successfully connected to the AWS RDS MySQL database.&lt;/p&gt;
&lt;h2&gt;Exercise 1: Create a Table&lt;/h2&gt;
&lt;p&gt;Create a 3 tables in the database, the tables are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SAILORS&lt;/code&gt; - Contains the details of the sailors.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SID&lt;/code&gt; - The ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SName&lt;/code&gt; - The name of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SRating&lt;/code&gt; - The rating of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SAge&lt;/code&gt; - The age of the sailor.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BOATS&lt;/code&gt; - Contains the details of the boats.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BID&lt;/code&gt; - The ID of the boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BName&lt;/code&gt; - The name of the boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BColor&lt;/code&gt; - The color of the boat.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RESERVES&lt;/code&gt; - Contains the details of the reservations.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SID&lt;/code&gt; - The ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BID&lt;/code&gt; - The ID of the boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Day&lt;/code&gt; - The day of the reservation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the SQL solution.&lt;/summary&gt;&lt;h3&gt;Create the SAILORS table&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE TABLE `SAI`.`SAILORS` (
    SID int auto_increment primary key,
    SName varchar(30) not null,
    SRating int default 0 check (SRating &amp;gt;= 0 and SRating &amp;lt;= 10),
    SAge real default 18 check (SAge &amp;gt;= 18 and SAge &amp;lt;= 70)
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation.&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SID&lt;/code&gt; - The ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SName&lt;/code&gt; - The name of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SRating&lt;/code&gt; - The rating of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SAge&lt;/code&gt; - The age of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auto_increment&lt;/code&gt; - The ID will be automatically incremented.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;primary key&lt;/code&gt; - The ID is the primary key of the table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;not null&lt;/code&gt; - The name of the sailor cannot be null.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default 0&lt;/code&gt; - The rating of the sailor will be 0 by default.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;check (SRating &amp;gt;= 0 and SRating &amp;lt;= 10)&lt;/code&gt; - The rating of the sailor must be between 0 and 10.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default 18&lt;/code&gt; - The age of the sailor will be 18 by default.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;check (SAge &amp;gt;= 18 and SAge &amp;lt;= 70)&lt;/code&gt; - The age of the sailor must be between 18 and 70.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;h3&gt;Create the BOATS table&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE TABLE `SAI`.`BOATS` (
    BID int auto_increment primary key,
    BName varchar(30) not null,
    BColor varchar(30) not null
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation.&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BID&lt;/code&gt; - The ID of the boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BName&lt;/code&gt; - The name of the boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BColor&lt;/code&gt; - The color of the boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auto_increment&lt;/code&gt; - The ID will be automatically incremented.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;primary key&lt;/code&gt; - The ID is the primary key of the table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;not null&lt;/code&gt; - The name of the boat cannot be null.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;h3&gt;Create the RESERVES table&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE TABLE `SAI`.`RESERVES` (
    SID int not null,
    BID int not null,
    Day date not null,
    primary key (SID, BID, Day),
);

alter table `SAI`.`RESERVES` add constraint `RESERVES_SAILORS_FK` foreign key (SID) references `SAI`.`SAILORS` (SID);
alter table `SAI`.`RESERVES` add constraint `RESERVES_BOATS_FK` foreign key (BID) references `SAI`.`BOATS` (BID);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation.&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SID&lt;/code&gt; - The ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BID&lt;/code&gt; - The ID of the boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Day&lt;/code&gt; - The day of the reservation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;primary key (SID, BID, Day)&lt;/code&gt; - The combination of the ID of the sailor, the ID of the boat and the day is the primary key of the table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;not null&lt;/code&gt; - The ID of the sailor, the ID of the boat and the day cannot be null.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;alter table&lt;/code&gt; - Add a foreign key to the table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RESERVES_SAILORS_FK&lt;/code&gt; - The name of the foreign key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foreign key (SID)&lt;/code&gt; - The ID of the sailor is the foreign key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;references&lt;/code&gt; - References the &lt;code&gt;SAILORS&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RESERVES_BOATS_FK&lt;/code&gt; - The name of the foreign key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foreign key (BID)&lt;/code&gt; - The ID of the boat is the foreign key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;references&lt;/code&gt; - References the &lt;code&gt;BOATS&lt;/code&gt; table.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;/details&gt;&lt;h3&gt;Insert data into the tables&lt;/h3&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the SQL solution.&lt;/summary&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (22, &amp;#39;Dustin&amp;#39;, 7, 45);
insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (29, &amp;#39;Brutus&amp;#39;, 1, 33);
insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (31, &amp;#39;Lubber&amp;#39;, 8, 55.5);
insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (32, &amp;#39;Andy&amp;#39;, 8, 25);
insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (58, &amp;#39;Rusty&amp;#39;, 10, 35);
insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (64, &amp;#39;Horatio&amp;#39;, 7, 35);
insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (71, &amp;#39;Zorba&amp;#39;, 10, 18);
insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (74, &amp;#39;Horatio&amp;#39;, 9, 40);
insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (85, &amp;#39;Art&amp;#39;, 3, 25.5);
insert into `SAI`.`SAILORS` (SID, SName, SRating, SAge) values (88, &amp;#39;Bob&amp;#39;, 3, 63.5);

insert into `SAI`.`BOATS` (BID, BName, BColor) values (101, &amp;#39;Interlake&amp;#39;, &amp;#39;blue&amp;#39;);
insert into `SAI`.`BOATS` (BID, BName, BColor) values (102, &amp;#39;Interlake&amp;#39;, &amp;#39;red&amp;#39;);
insert into `SAI`.`BOATS` (BID, BName, BColor) values (103, &amp;#39;Clipper&amp;#39;, &amp;#39;green&amp;#39;);
insert into `SAI`.`BOATS` (BID, BName, BColor) values (104, &amp;#39;Marine&amp;#39;, &amp;#39;red&amp;#39;);

insert into `SAI`.`RESERVES` (SID, BID, Day) values (22, 101, &amp;#39;1998-10-10&amp;#39;);
insert into `SAI`.`RESERVES` (SID, BID, Day) values (22, 102, &amp;#39;1998-10-10&amp;#39;);
insert into `SAI`.`RESERVES` (SID, BID, Day) values (22, 103, &amp;#39;1998-10-8&amp;#39;);
insert into `SAI`.`RESERVES` (SID, BID, Day) values (22, 104, &amp;#39;1998-10-7&amp;#39;);
insert into `SAI`.`RESERVES` (SID, BID, Day) values (31, 102, &amp;#39;1998-11-10&amp;#39;);
insert into `SAI`.`RESERVES` (SID, BID, Day) values (31, 103, &amp;#39;1998-11-6&amp;#39;);
insert into `SAI`.`RESERVES` (SID, BID, Day) values (31, 104, &amp;#39;1998-11-12&amp;#39;);
insert into `SAI`.`RESERVES` (SID, BID, Day) values (64, 101, &amp;#39;1998-9-5&amp;#39;);
insert into `SAI`.`RESERVES` (SID, BID, Day) values (64, 102, &amp;#39;1998-9-8&amp;#39;);
insert into `SAI`.`RESERVES` (SID, BID, Day) values (64, 103, &amp;#39;1998-9-8&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;Exercise 2: Write a Querys&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Find all information of sailors who have reserved boat number 101.&lt;/li&gt;
&lt;li&gt;Find the names of sailors who have reserved a red boat, and list in the order of age.&lt;/li&gt;
&lt;li&gt;Find the names of sailors who have reserved at least one boat.&lt;/li&gt;
&lt;li&gt;Find the ids and names of sailors who have reserved two different boats on the same day.&lt;/li&gt;
&lt;li&gt;Find the ids of sailors who have reserved a red boat or a green boat&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the SQL solution.&lt;/summary&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select * from `SAI`.`SAILORS`
where SID in (
    select SID from `SAI`.`RESERVES`
    where BID = 101
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation.&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;select *&lt;/code&gt; - Select all columns.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;SAILORS&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the ID of the sailor is in the list of IDs of sailors who have reserved boat number 101.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SID in&lt;/code&gt; - The ID of the sailor is in the list.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select SID&lt;/code&gt; - Select the ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;RESERVES&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the ID of the boat is 101.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select SName from `SAI`.`SAILORS`
WHERE SID in (
    select SID from `SAI`.`RESERVES`
    WHERE BID in (
        select BID from `SAI`.`BOATS`
        WHERE BColor = &amp;#39;red&amp;#39;
    )
)
order by SAge;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation.&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;select SName&lt;/code&gt; - Select the name of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;SAILORS&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the ID of the sailor is in the list of IDs of sailors who have reserved a red boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SID in&lt;/code&gt; - The ID of the sailor is in the list.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select SID&lt;/code&gt; - Select the ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;RESERVES&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the ID of the boat is in the list of IDs of red boats.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BID in&lt;/code&gt; - The ID of the boat is in the list.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select BID&lt;/code&gt; - Select the ID of the boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;BOATS&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the color of the boat is red.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order by&lt;/code&gt; - Order by the age of the sailor.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select SName from `SAI`.`SAILORS`
where SID in (
    select SID from `SAI`.`RESERVES`
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation.&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;select SName&lt;/code&gt; - Select the name of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;SAILORS&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the ID of the sailor is in the list of IDs of sailors who have reserved a boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SID in&lt;/code&gt; - The ID of the sailor is in the list.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select SID&lt;/code&gt; - Select the ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;RESERVES&lt;/code&gt; table.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select SID from `SAI`.`SAILORS`
where SID in (
    select SID from `SAI`.`RESERVES`
    group by SID, Day
    having count(*) = 2
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation.&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;select SID&lt;/code&gt; - Select the ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;SAILORS&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the ID of the sailor is in the list of IDs of sailors who have reserved two boats on the same day.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SID in&lt;/code&gt; - The ID of the sailor is in the list.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select SID&lt;/code&gt; - Select the ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;RESERVES&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;group by&lt;/code&gt; - Group by the ID of the sailor and the day.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;having&lt;/code&gt; - Having the count of the number of boats reserved is 2.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select SID from `SAI`.`SAILORS`
where SID in (
    select SID from `SAI`.`RESERVES`
    where BID in (
        select BID from `SAI`.`BOATS`
        where BColor = &amp;#39;red&amp;#39;
    )
)
or SID in (
    select SID from `SAI`.`RESERVES`
    where BID in (
        select BID from `SAI`.`BOATS`
        where BColor = &amp;#39;green&amp;#39;
    )
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Click to expand the explanation.&lt;/summary&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;select SID&lt;/code&gt; - Select the ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;SAILORS&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the ID of the sailor is in the list of IDs of sailors who have reserved a red boat or a green boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SID in&lt;/code&gt; - The ID of the sailor is in the list.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select SID&lt;/code&gt; - Select the ID of the sailor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;RESERVES&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the ID of the boat is in the list of IDs of red boats or green boats.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BID in&lt;/code&gt; - The ID of the boat is in the list.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select BID&lt;/code&gt; - Select the ID of the boat.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - From the &lt;code&gt;BOATS&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt; - Where the color of the boat is red or green.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;&lt;/details&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, you learned how to create a RDS instance, how to connect to it, and how to create a database and tables. You also learned how to insert data into the tables and how to write queries to retrieve data from the tables. You can use these skills to create a database for your own projects.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html&quot;&gt;Amazon RDS User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_CreateDBInstance.html&quot;&gt;Creating an Amazon RDS DB instance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ConnectToInstance.html&quot;&gt;Connecting to a DB instance running the MySQL database engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/workbench/en/&quot;&gt;MySQL Workbench Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/&quot;&gt;MySQL 8.0 Reference Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/sql/&quot;&gt;SQL Tutorial - W3Schools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/rds/mysql/&quot;&gt;Amazon RDS for MySQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html#Welcome.Security&quot;&gt;Security in Amazon RDS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html&quot;&gt;VPC security groups&lt;/a&gt; (Relevant for RDS access)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/create-table.html&quot;&gt;MySQL CREATE TABLE Statement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/insert.html&quot;&gt;MySQL INSERT Statement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/select.html&quot;&gt;MySQL SELECT Statement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html&quot;&gt;MySQL Foreign Key Constraints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/console/&quot;&gt;AWS Console Home&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>RDS</category><category>MySQL</category><category>Database Management</category><category>Cloud Computing</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0017-how-to-create-a-aws-rds-mysql-database-and-connect-to-it-using-mysql-workbench/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Run an Apache Web Server Using Docker on an AWS EC2 Instance</title><link>https://mkabumattar.com/blog/post/how-to-run-an-apache-web-server-using-docker-on-an-aws-ec2-instance/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-run-an-apache-web-server-using-docker-on-an-aws-ec2-instance/</guid><description>We will learn how to create an AWS EC2 instance using AWS CLI in this tutorial. We will also discover how to set up an AWS EC2 instance so that it functions with the Apache web server. We will also discover how to set up an AWS EC2 instance so that it functions with WordPress.</description><pubDate>Mon, 31 Oct 2022 09:18:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post, we will learn how to run an Apache web server using Docker on an AWS EC2 instance. We will use the following tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/ec2/&quot;&gt;AWS EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/&quot;&gt;Apache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An AWS account&lt;/li&gt;
&lt;li&gt;An AWS EC2 instance&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;
  You can follow this tutorial to create an [AWS EC2 instance Using AWS
  CLI](/blog/post/how-to-create-an-aws-ec2-instance-using-aws-cli) wthout using
  user data, or you can create an AWS EC2 instance using the AWS console.
&lt;/Notice&gt;&lt;h2&gt;Setup and Configure Docker to Run an Apache Web Server on an AWS EC2 Instance&lt;/h2&gt;
&lt;h3&gt;Step 1: Install Docker on the AWS EC2 Instance&lt;/h3&gt;
&lt;p&gt;Before we can install Docker on the AWS EC2 instance, we need to update the package list.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo yum update -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to install Docker on the AWS EC2 instance.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo amazon-linux-extras install docker -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Start the Docker Service&lt;/h3&gt;
&lt;p&gt;After installing Docker on the AWS EC2 instance, we need to start the Docker service.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo service docker start
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Add the &lt;code&gt;ec2-user&lt;/code&gt; to the Docker Group&lt;/h3&gt;
&lt;p&gt;Try to run the following command to check if the Docker service is running.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker info
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker info&lt;/code&gt; - This command will show the information about the Docker service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you get the following error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Client:
  Context:    default
  Debug Mode: false

Server:
  ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
errors pretty printing info
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you need to add the &lt;code&gt;ec2-user&lt;/code&gt; to the Docker group.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo usermod -a -G docker ec2-user
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Exit the SSH session and reconnect to the AWS EC2 instance.&lt;/p&gt;
&lt;p&gt;After reconnecting to the AWS EC2 instance, try to run the following command again.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker info
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you get the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Client:
  Context:    default
  Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 20.10.17
 Storage Driver: overlay2
  Backing Filesystem: xfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1
 runc version: 1e7bb5b773162b57333d57f612fd72e3f8612d94
 init version: de40ad0
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 5.10.144-127.601.amzn2.x86_64
 Operating System: Amazon Linux 2
 OSType: linux
 Architecture: x86_64
 CPUs: 1
 Total Memory: 964.8MiB
 Name: ip-172-31-95-171.ec2.internal
 ID: VWQG:27RB:ARKI:V77B:34E2:BRGC:6DDJ:EKSF:VUQP:TX5G:UXVF:Q444
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you have successfully installed Docker on the AWS EC2 instance.&lt;/p&gt;
&lt;h3&gt;Step 4: Run the Apache Web Server Using Docker&lt;/h3&gt;
&lt;p&gt;First, we need to pull the Apache image from Docker Hub.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker pull httpd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker pull&lt;/code&gt; - Pull an image or a repository from a registry like &lt;a href=&quot;https://hub.docker.com/&quot;&gt;Docker Hub&lt;/a&gt;, or from a private registry like &lt;a href=&quot;https://aws.amazon.com/ecr/&quot;&gt;AWS ECR&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, we need to run the Apache web server using Docker.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run -dit --name apache -p 80:80 httpd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker run&lt;/code&gt; - Run a command in a new container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-dit&lt;/code&gt; - Run container in background and print container ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--name&lt;/code&gt; - Assign a name to the container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Publish a container&amp;#39;s port(s) to the host.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;httpd&lt;/code&gt; - The image name.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Test the Apache Web Server&lt;/h3&gt;
&lt;p&gt;To test the Apache web server, we need to get the public IP address of the AWS EC2 instance.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl http://PUBLIC_IP_ADDRESS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, we can use the the private IP address of the AWS EC2 instance.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl http://PRIVATE_IP_ADDRESS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you get the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;It works!&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, the Apache web server is running successfully.&lt;/p&gt;
&lt;h3&gt;Step 6: Edit The Web Page on Docker Container&lt;/h3&gt;
&lt;p&gt;To edit the web page, we need to open the &lt;code&gt;index.html&lt;/code&gt; file, in the &lt;code&gt;/usr/local/apache2/htdocs&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Before we can edit the &lt;code&gt;index.html&lt;/code&gt; file, we need to get the container ID of the Apache container.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker ps&lt;/code&gt; - List containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, we need to open the Docker container.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker exec -it CONTAINER_ID /bin/bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker exec&lt;/code&gt; - Run a command in a running container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-it&lt;/code&gt; - Keep STDIN open even if not attached.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CONTAINER_ID&lt;/code&gt; - The container ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/bin/bash&lt;/code&gt; - The command to run.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, we need to open the &lt;code&gt;index.html&lt;/code&gt; file, in the &lt;code&gt;/usr/local/apache2/htdocs&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;vi /usr/local/apache2/htdocs/index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you get the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;bash: vi: command not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you need to install the &lt;code&gt;vi&lt;/code&gt; editor.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# update the package list
apt-get update -y

# upgrade the packages
apt-get upgrade -y

# install the vi editor
apt-get install -y vim
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to open the &lt;code&gt;index.html&lt;/code&gt; file, in the &lt;code&gt;/usr/local/apache2/htdocs&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;vi /usr/local/apache2/htdocs/index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to add the following content to the &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to save the &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;:wq
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to exit the Docker container.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to refresh the web page.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl http://PUBLIC_IP_ADDRESS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you get the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, the web page has been updated successfully.&lt;/p&gt;
&lt;h3&gt;Step 7: Stop the Docker Container&lt;/h3&gt;
&lt;p&gt;To stop the Docker container, we need to get the container ID of the Apache container.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# To get the Docker container ID
docker ps

# To stop the Apache web server
docker stop CONTAINER_ID

# Or, you can use the container name
docker stop apache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, you can stop all the Docker containers using the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker stop $(docker ps -a -q)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker ps&lt;/code&gt; - List containers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker stop&lt;/code&gt; - Stop one or more running containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 8: Restart the Docker Container&lt;/h3&gt;
&lt;p&gt;To restart the Docker container by using the container name, we need to run the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker start apache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker start&lt;/code&gt; - Start one or more stopped containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 9: Remove the Docker Container&lt;/h3&gt;
&lt;p&gt;To remove the Docker container, we need to get the container ID of the Apache container.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# To get the Docker container ID
docker ps -a

# To remove the Apache web server
docker rm CONTAINER_ID

# Or, you can use the container name
docker rm apache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, you can remove all the Docker containers using the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker rm $(docker ps -a -q)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker ps&lt;/code&gt; - List containers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker rm&lt;/code&gt; - Remove one or more containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 10: Remove the Docker Image&lt;/h3&gt;
&lt;p&gt;To remove the Docker image, we need to get the image ID of the Apache image.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# To get the Docker image ID
docker images

# To remove the Apache web server
docker rmi IMAGE_ID

# Or, you can use the image name
docker rmi httpd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, you can remove all the Docker images using the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker rmi $(docker images -q)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker images&lt;/code&gt; - List images.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker rmi&lt;/code&gt; - Remove one or more images.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post, we learned how to run an Apache web server using Docker on an AWS EC2 instance. We also learned how to update and install packages on Docker containers.&lt;/p&gt;
&lt;Notice type=&quot;note&quot;&gt;
  If you have any questions, please leave a comment below..
&lt;/Notice&gt;&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/_/httpd&quot;&gt;Docker Hub - httpd (Apache HTTP Server)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html&quot;&gt;Install Docker Engine on Amazon Linux 2&lt;/a&gt; (Though the post uses &lt;code&gt;amazon-linux-extras&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/amazon-linux-2/faqs/#Amazon_Linux_Extras&quot;&gt;Amazon Linux Extras library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/&quot;&gt;Apache HTTP Server Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/run/&quot;&gt;Docker CLI &lt;code&gt;run&lt;/code&gt; command reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/pull/&quot;&gt;Docker CLI &lt;code&gt;pull&lt;/code&gt; command reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/ps/&quot;&gt;Docker CLI &lt;code&gt;ps&lt;/code&gt; command reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/exec/&quot;&gt;Docker CLI &lt;code&gt;exec&lt;/code&gt; command reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/stop/&quot;&gt;Docker CLI &lt;code&gt;stop&lt;/code&gt; command reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/rm/&quot;&gt;Docker CLI &lt;code&gt;rm&lt;/code&gt; command reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/images/&quot;&gt;Docker CLI &lt;code&gt;images&lt;/code&gt; command reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/rmi/&quot;&gt;Docker CLI &lt;code&gt;rmi&lt;/code&gt; command reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/linux-postinstall/&quot;&gt;Post-installation steps for Linux - Manage Docker as a non-root user&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>EC2</category><category>Docker</category><category>Apache</category><category>Web Server</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0016-how-to-run-an-apache-web-server-using-docker-on-an-aws-ec2-instance/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Create An AWS EC2 Instance Using AWS CLI</title><link>https://mkabumattar.com/blog/post/how-to-create-an-aws-ec2-instance-using-aws-cli/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-create-an-aws-ec2-instance-using-aws-cli/</guid><description>We will learn how to create an AWS EC2 instance using AWS CLI in this tutorial. We will also discover how to set up an AWS EC2 instance so that it functions with the Apache web server. We will also discover how to set up an AWS EC2 instance so that it functions with WordPress.</description><pubDate>Sun, 30 Oct 2022 03:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;We will learn how to create an AWS EC2 instance using AWS CLI in this tutorial. We will also discover how to set up an AWS EC2 instance so that it functions with the Apache web server. We will also discover how to set up an AWS EC2 instance so that it functions with WordPress.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow along with this tutorial, you will need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An AWS account.&lt;/li&gt;
&lt;li&gt;An AWS IAM user with the following permissions:&lt;ul&gt;
&lt;li&gt;AmazonEC2FullAccess&lt;/li&gt;
&lt;li&gt;AmazonVPCFullAccess&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;An AWS CLI installed on your computer.&lt;/li&gt;
&lt;li&gt;An SSH client installed on your computer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create an AWS VPC&lt;/h2&gt;
&lt;p&gt;Before we create an AWS EC2 instance using AWS CLI, we need to create a VPC. We will also create a public and private subnet, an internet gateway, and a route table.&lt;/p&gt;
&lt;h3&gt;Create an VPC&lt;/h3&gt;
&lt;p&gt;To create a VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a VPC
AWS_VPC=$(aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--query &amp;#39;Vpc.{VpcId:VpcId}&amp;#39; \
--output text)

# Add a name tag to the VPC
aws ec2 create-tags \
--resources $AWS_VPC \
--tags Key=Name,Value=DevOpsVPC
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Modify your custom VPC and enable DNS hostname support, and DNS support&lt;/h3&gt;
&lt;p&gt;To modify your custom VPC and enable DNS hostname support, and DNS support, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable DNS hostnames
aws ec2 modify-vpc-attribute \
--vpc-id $AWS_VPC \
--enable-dns-hostnames &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;

# Enable DNS support
aws ec2 modify-vpc-attribute \
--vpc-id $AWS_VPC \
--enable-dns-support &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a Public Subnet&lt;/h3&gt;
&lt;p&gt;To create a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a public subnet
AWS_PUBLIC_SUBNET=$(aws ec2 create-subnet \
--vpc-id $AWS_VPC \
--cidr-block 10.0.1.0/24 \
--availability-zone us-east-1a \
--query &amp;#39;Subnet.{SubnetId:SubnetId}&amp;#39; \
--output text)

# Add a name tag to the public subnet
aws ec2 create-tags \
--resources $AWS_PUBLIC_SUBNET \
--tags Key=Name,Value=DevOpsPublicSubnet
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a Private Subnet&lt;/h3&gt;
&lt;p&gt;To create a private subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# create a private subnet
AWS_PRIVATE_SUBNET=$(aws ec2 create-subnet \
--vpc-id $AWS_VPC \
--cidr-block 10.0.2.0/24 \
--availability-zone us-east-1a \
--query &amp;#39;Subnet.{SubnetId:SubnetId}&amp;#39; \
--output text)

# Add a name tag to the private subnet
aws ec2 create-tags \
--resources $AWS_PRIVATE_SUBNET \
--tags Key=Name,Value=DevOpsPrivateSubnet
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Enable Auto-assign Public IP on the subnet&lt;/h3&gt;
&lt;p&gt;To enable auto-assign public IP on the subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable auto-assign public IP on the public subnet
aws ec2 modify-subnet-attribute \
--subnet-id $AWS_PUBLIC_SUBNET \
--map-public-ip-on-launch
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create an Internet Gateway&lt;/h3&gt;
&lt;p&gt;To create an internet gateway, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;AWS_INTERNET_GATEWAY=$(aws ec2 create-internet-gateway \
--query &amp;#39;InternetGateway.{InternetGatewayId:InternetGatewayId}&amp;#39; \
--output text)

# Add a name tag to the Internet Gateway
aws ec2 create-tags \
--resources $AWS_INTERNET_GATEWAY \
--tags Key=Name,Value=DevOpsInternetGateway
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create an NAT gateway&lt;/h3&gt;
&lt;p&gt;To create an NAT gateway, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get Elastic IP
AWS_ELASTIC_IP=$(aws ec2 allocate-address \
--domain vpc \
--query &amp;#39;AllocationId&amp;#39; \
--output text)

# Create a NAT gateway
AWS_NAT_GATEWAY=$(aws ec2 create-nat-gateway \
--subnet-id $AWS_PUBLIC_SUBNET \
--allocation-id $AWS_EIP_ALLOCATION \
--query &amp;#39;NatGateway.{NatGatewayId:NatGatewayId}&amp;#39; \
--output text)

# Add a name tag to the NAT gateway
aws ec2 create-tags \
--resources $AWS_NAT_GATEWAY \
--tags Key=Name,Value=DevOpsNATGateway
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Attach the Internet gateway to your VPC&lt;/h3&gt;
&lt;p&gt;To attach the Internet gateway to your VPC, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the Internet gateway to your VPC
aws ec2 attach-internet-gateway \
--vpc-id $AWS_VPC \
--internet-gateway-id $AWS_INTERNET_GATEWAY \
--query &amp;#39;InternetGateway.{InternetGatewayId:InternetGatewayId}&amp;#39; \
--output text
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a custom route table&lt;/h3&gt;
&lt;p&gt;To create a route table, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a custom route table
AWS_ROUTE_TABLE=$(aws ec2 create-route-table \
--vpc-id $AWS_VPC \
--query &amp;#39;RouteTable.{RouteTableId:RouteTableId}&amp;#39; \
--output text)

# Add a name tag to the route table
aws ec2 create-tags \
--resources $AWS_ROUTE_TABLE \
--tags Key=Name,Value=DevOpsRouteTable
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a custom route table association&lt;/h3&gt;
&lt;p&gt;To create a custom route table association, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a custom route table association
aws ec2 associate-route-table \
--route-table-id $AWS_ROUTE_TABLE \
--subnet-id $AWS_PUBLIC_SUBNET \
--output text
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Associate the subnet with route table, making it a public subnet&lt;/h3&gt;
&lt;p&gt;To associate the subnet with route table, making it a public subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the subnet with route table, making it a public subnet
aws ec2 create-route \
--route-table-id $AWS_ROUTE_TABLE \
--destination-cidr-block 0.0.0.0/0 \
--gateway-id $AWS_INTERNET_GATEWAY \
--output text
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Associate the NAT gateway with the route table, making it a private subnet&lt;/h3&gt;
&lt;p&gt;To associate the NAT gateway with the route table, making it a private subnet, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the NAT gateway with the route table, making it a private subnet
aws ec2 create-route \
--route-table-id $AWS_ROUTE_TABLE \
--destination-cidr-block 10.2.0.0/24 \
--nat-gateway-id $AWS_NAT_GATEWAY \
--output text
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a security group&lt;/h3&gt;
&lt;p&gt;To create a security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a security group
AWS_SECURITY_GROUP=$(aws ec2 create-security-group \
--group-name DevOpsSG \
--description &amp;quot;DevOps Security Group&amp;quot; \
--vpc-id $AWS_VPC \
--query &amp;#39;GroupId&amp;#39; \
--output text)

# Add a name tag to the security group
aws ec2 create-tags \
--resources $AWS_SECURITY_GROUP \
--tags Key=Name,Value=DevOpsSG
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Add a rule to the security group&lt;/h3&gt;
&lt;p&gt;To add a rule to the security group, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add a rule to the security group

# Add SSH rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 22 \
--cidr 0.0.0.0/0 \
--output text

# Add HTTP rule
aws ec2 authorize-security-group-ingress \
--group-id $AWS_SECURITY_GROUP \
--protocol tcp \
--port 80 \
--cidr 0.0.0.0/0 \
--output text
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create an AWS EC2 instance&lt;/h2&gt;
&lt;h3&gt;Get the latest AMI ID&lt;/h3&gt;
&lt;p&gt;To get the latest AMI ID, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the latest AMI ID
AWS_AMI=$(aws ec2 describe-images \
  --owners &amp;#39;amazon&amp;#39; \
  --filters &amp;#39;Name=name,Values=amzn2-ami-hvm-2.0.*&amp;#39; \
  &amp;#39;Name=state,Values=available&amp;#39; \
  --query &amp;#39;sort_by(Images, &amp;amp;CreationDate)[-1].[ImageId]&amp;#39; \
  --output &amp;#39;text&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a key pair&lt;/h3&gt;
&lt;p&gt;To create a key pair, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a key pair
aws ec2 create-key-pair \
--key-name DevOpsKeyPair \
--query &amp;#39;KeyMaterial&amp;#39; \
--output text &amp;gt; DevOpsKeyPair.pem

# Change the permission of the key pair
chmod 400 DevOpsKeyPair.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create an EC2 instance&lt;/h3&gt;
&lt;p&gt;Before creating an EC2 instance, you need to create a user data script. That script will be automation previous three blog posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/how-to-install-apache-web-server-on-amazon-linux-2&quot;&gt;How to Install Apache Web Server on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/how-to-install-php-and-mariadb-on-amazon-linux-2&quot;&gt;How to Install PHP and MariaDB on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/0015-how-to-create-an-aws-ec2-instance-using-aws-cli/how-to-create-an-aws-ec2-instance-using-aws-cli&quot;&gt;How To Create An AWS EC2 Instance Using AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find the user data script in the &lt;a href=&quot;https://github.com/MKAbuMattar/install-and-setup-wordpress-on-amazon-linux-2&quot;&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a bash script to update packages, install git and clone the repo, and run the script
cat &amp;lt;&amp;lt;EOF &amp;gt; install.sh
#!/bin/bash

# Update packages
sudo yum update -y

# Install git
sudo yum install git -y

# Clone the repo
git clone https://github.com/MKAbuMattar/install-and-setup-wordpress-on-amazon-linux-2.git

# Run the script
bash install-and-setup-wordpress-on-amazon-linux-2/script.sh mkabumattar 121612 121612 wordpressdb wordpressuser password
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To create an EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an EC2 instance
AWS_EC2_INSTANCE=$(aws ec2 run-instances \
--image-id $AWS_AMI \
--instance-type t2.micro \
--key-name DevOpsKeyPair \
--monitoring &amp;quot;Enabled=false&amp;quot; \
--security-group-ids $AWS_SECURITY_GROUP \
--subnet-id $AWS_PUBLIC_SUBNET \
--user-data file://install.sh \
--private-ip-address 10.0.1.10 \
--query &amp;#39;Instances[0].InstanceId&amp;#39; \
--output text)

# Add a name tag to the EC2 instance
aws ec2 create-tags \
--resources $AWS_EC2_INSTANCE \
--tags &amp;quot;Key=Name,Value=DevOpsInstance&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Check the status of the EC2 instance&lt;/h3&gt;
&lt;p&gt;To check the status of the EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Check the status of the EC2 instance
aws ec2 describe-instances \
--instance-ids $AWS_EC2_INSTANCE \
--query &amp;#39;Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress]&amp;#39; \
--output text
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Get the public ip address of your instance&lt;/h3&gt;
&lt;p&gt;To get the public ip address of your instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the public ip address of your instance
AWS_PUBLIC_IP=$(aws ec2 describe-instances \
--instance-ids $AWS_EC2_INSTANCE \
--query &amp;#39;Reservations[*].Instances[*].[PublicIpAddress]&amp;#39; \
--output text)

echo $AWS_EC2_INSTANCE_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;SSH into the EC2 instance&lt;/h3&gt;
&lt;p&gt;To SSH into the EC2 instance, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# SSH into the EC2 instance
ssh -i DevOpsKeyPair.pem ec2-user@$AWS_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Show the WordPress website&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0015-how-to-create-an-aws-ec2-instance-using-aws-cli/wordpress-on-amazon-linux-2-1.png&quot; alt=&quot;WordPress on Amazon Linux 2&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this blog post, you learned how to create a VPC, a public subnet, a private subnet, a NAT gateway, a route table, a security group, and an EC2 instance. You also learned how to SSH into the EC2 instance.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/index.html&quot;&gt;AWS CLI Command Reference - EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-vpc.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-vpc&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-subnet.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-subnet&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-internet-gateway.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-internet-gateway&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-nat-gateway.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-nat-gateway&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-route-table.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-route-table&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-security-group.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-security-group&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/run-instances.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 run-instances&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-key-pair.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-key-pair&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html&quot;&gt;Amazon EC2 User Guide for Linux Instances - User Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&quot;&gt;Amazon VPC User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wordpress.org/&quot;&gt;WordPress Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html&quot;&gt;Tutorial: Installing a LAMP Web Server on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/MKAbuMattar/install-and-setup-wordpress-on-amazon-linux-2&quot;&gt;GitHub Repository for User Data Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html&quot;&gt;AWS Identity and Access Management (IAM) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>EC2</category><category>VPC</category><category>AWS CLI</category><category>WordPress</category><category>Linux</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0015-how-to-create-an-aws-ec2-instance-using-aws-cli/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Install WordPress on Amazon Linux 2</title><link>https://mkabumattar.com/blog/post/how-to-install-wordpress-on-amazon-linux-2/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-install-wordpress-on-amazon-linux-2/</guid><description>We will learn how to install WordPress on Amazon Linux 2 in this tutorial. We will also discover how to set up WordPress so that it functions with the Apache web server. We will also discover how to set up WordPress so that it functions with PHP and MariaDB.</description><pubDate>Mon, 24 Oct 2022 03:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;We will learn how to install WordPress on Amazon Linux 2 in this tutorial. We will also discover how to set up WordPress so that it functions with the Apache web server. We will also discover how to set up WordPress so that it functions with PHP and MariaDB.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow along with this tutorial, you will need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Amazon Linux 2 EC2 instance with a public IP address.&lt;/li&gt;
&lt;li&gt;A non-root user with sudo privileges.&lt;/li&gt;
&lt;li&gt;A domain name pointing to the public IP address of your EC2 instance.&lt;/li&gt;
&lt;li&gt;Apache web server installed and running. &lt;a href=&quot;/blog/post/how-to-install-apache-web-server-on-amazon-linux-2&quot;&gt;How to Install Apache Web Server on Amazon Linux 2&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;PHP installed and running. &lt;a href=&quot;/blog/post/how-to-install-php-and-mariadb-on-amazon-linux-2&quot;&gt;How to Install WordPress on Amazon Linux 2&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Installing WordPress, setting up WordPress, and running a basic WordPress demo&lt;/h2&gt;
&lt;h3&gt;Step 1 Download WordPress&lt;/h3&gt;
&lt;p&gt;WordPress is a free and open-source content management system (CMS) based on PHP and MySQL. It is the most popular CMS in the world.&lt;/p&gt;
&lt;p&gt;To download WordPress, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo wget https://wordpress.org/latest.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2 Extract WordPress&lt;/h3&gt;
&lt;p&gt;To extract the WordPress archive, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo tar -xzvf latest.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, move the extracted WordPress directory to the &lt;code&gt;/var/www/html&lt;/code&gt; directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo mv wordpress /var/www/html/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3 Create a WordPress Database&lt;/h3&gt;
&lt;p&gt;To create a WordPress database, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo mysql -u root -p
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, create a database for WordPress:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE DATABASE wordpress;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, create a user for WordPress:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE USER &amp;#39;wordpressuser&amp;#39;@&amp;#39;localhost&amp;#39; IDENTIFIED BY &amp;#39;password&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, grant all privileges to the WordPress user:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;GRANT ALL PRIVILEGES ON wordpress.* TO &amp;#39;wordpressuser&amp;#39;@&amp;#39;localhost&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, flush the privileges:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;FLUSH PRIVILEGES;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, exit the MySQL shell:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;exit
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4 Configure WordPress&lt;/h3&gt;
&lt;p&gt;To configure WordPress, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo cp /var/www/html/wordpress/wp-config-sample.php /var/www/html/wordpress/wp-config.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, open the WordPress configuration file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo vi /var/www/html/wordpress/wp-config.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, update the database name, user, and password:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;/** The name of the database for WordPress */
define(&amp;#39;DB_NAME&amp;#39;, &amp;#39;wordpress&amp;#39;);
/** Database username */
define(&amp;#39;DB_USER&amp;#39;, &amp;#39;wordpressuser&amp;#39;);
/** Database password */
define(&amp;#39;DB_PASSWORD&amp;#39;, &amp;#39;password&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, save and close the file.&lt;/p&gt;
&lt;h3&gt;Step 5 Set Up WordPress&lt;/h3&gt;
&lt;p&gt;To set up WordPress, open your web browser and navigate to your domain name. For example, &lt;code&gt;https://example.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, click on the &lt;strong&gt;Let’s go!&lt;/strong&gt; button.&lt;/p&gt;
&lt;p&gt;Next, enter the site title, username, password, and email address:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0014-how-to-install-wordpress-on-amazon-linux-2/wordpress-site-title-username-password-and-email-address.png&quot; alt=&quot;WordPress Site Title, Username, Password, and Email Address&quot;&gt;&lt;/p&gt;
&lt;p&gt;Next, click on the &lt;strong&gt;Install WordPress&lt;/strong&gt; button.&lt;/p&gt;
&lt;p&gt;Next, click on the &lt;strong&gt;Log In&lt;/strong&gt; button.&lt;/p&gt;
&lt;p&gt;Next, enter the username and password:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0014-how-to-install-wordpress-on-amazon-linux-2/wordpress-username-and-password.png&quot; alt=&quot;WordPress Username and Password&quot;&gt;&lt;/p&gt;
&lt;p&gt;Next, click on the &lt;strong&gt;Log In&lt;/strong&gt; button.&lt;/p&gt;
&lt;p&gt;Now, you have successfully installed WordPress on Amazon Linux 2.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0014-how-to-install-wordpress-on-amazon-linux-2/wordpress-dashboard.png&quot; alt=&quot;WordPress Dashboard&quot;&gt;&lt;/p&gt;
&lt;br /&gt;&lt;Notice type=&quot;note&quot;&gt;
  Remember to protect your WordPress Admin Panel and cover up the URL and
  WordPress version.
&lt;/Notice&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to install WordPress on Amazon Linux 2. We also discovered how to set up WordPress so that it functions with the Apache web server. We also discovered how to set up WordPress so that it functions with PHP and MariaDB.&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wordpress.org/download/&quot;&gt;WordPress Official Website - Download&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wordpress.org/support/article/how-to-install-wordpress/&quot;&gt;WordPress Codex - Installing WordPress&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wordpress.org/support/article/editing-wp-config-php/&quot;&gt;WordPress Codex - Editing wp-config.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/hosting-wordpress.html&quot;&gt;AWS Tutorial: Host a WordPress blog on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/docs/&quot;&gt;Apache HTTP Server Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/&quot;&gt;PHP Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mariadb.com/kb/en/documentation/&quot;&gt;MariaDB Server Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/create-database.html&quot;&gt;MySQL CREATE DATABASE Statement&lt;/a&gt; (MariaDB syntax is similar)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/create-user.html&quot;&gt;MySQL CREATE USER Statement&lt;/a&gt; (MariaDB syntax is similar)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/grant.html&quot;&gt;MySQL GRANT Statement&lt;/a&gt; (MariaDB syntax is similar)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/how-to-install-apache-web-server-on-amazon-linux-2&quot;&gt;Previous Post: How to Install Apache Web Server on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/how-to-install-php-and-mariadb-on-amazon-linux-2&quot;&gt;Previous Post: How to Install PHP and MariaDB on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/wget/manual/wget.html&quot;&gt;wget Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/tar/manual/tar.html&quot;&gt;tar Manual&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>EC2</category><category>WordPress</category><category>LAMP Stack</category><category>Linux</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0014-how-to-install-wordpress-on-amazon-linux-2/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Install PHP and MariaDB on Amazon Linux 2</title><link>https://mkabumattar.com/blog/post/how-to-install-php-and-mariadb-on-amazon-linux-2/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-install-php-and-mariadb-on-amazon-linux-2/</guid><description>We will learn how to set up PHP and MariaDB on Amazon Linux 2 in this tutorial. We will also discover how to set up PHP so that it functions with the Apache web server. We will also discover how to set up MariaDB so that it functions with PHP.</description><pubDate>Mon, 24 Oct 2022 02:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;We will learn how to set up PHP and MariaDB on Amazon Linux 2 in this tutorial. We will also discover how to set up PHP so that it functions with the Apache web server. We will also discover how to set up MariaDB so that it functions with PHP.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow along with this tutorial, you will need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Amazon Linux 2 EC2 instance with a public IP address.&lt;/li&gt;
&lt;li&gt;A non-root user with sudo privileges.&lt;/li&gt;
&lt;li&gt;A domain name pointing to the public IP address of your EC2 instance.&lt;/li&gt;
&lt;li&gt;Apache web server installed and running. &lt;a href=&quot;/blog/post/how-to-install-apache-web-server-on-amazon-linux-2&quot;&gt;How to Install PHP and MariaDB on Amazon Linux 2&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Installing PHP/MariaDB, setting up MariaDB, and running a basic PHP demo&lt;/h2&gt;
&lt;h3&gt;Step 1 Installing PHP&lt;/h3&gt;
&lt;p&gt;PHP is a free and open-source scripting language that is used to create dynamic web pages. It is the most popular web scripting language in the world.&lt;/p&gt;
&lt;p&gt;At first, we will enable &lt;code&gt;amazon-linux-extras&lt;/code&gt; so that we can specify the PHP version that we want to install.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo amazon-linux-extras enable php7.4 -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we will install PHP.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo yum install php php-{pear,cgi,common,curl,mbstring,gd,mysqlnd,gettext,bcmath,json,xml,fpm,intl,zip,imap} -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will now verify that PHP has been installed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;php -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;PHP 7.4.30 (cli) (built: Jun 23 2022 20:19:00) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2 Installing MariaDB&lt;/h3&gt;
&lt;p&gt;MariaDB is a free and open-source relational database management system (RDBMS) that is used to store data for dynamic web pages. It is a fork of MySQL.&lt;/p&gt;
&lt;p&gt;At first, we will install MariaDB.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo yum install mariadb-server -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we will start MariaDB.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo systemctl start mariadb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will configure MariaDB so that it starts automatically when the system boots.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo systemctl enable mariadb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will now secure MariaDB.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo mysql_secure_installation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be prompted to enter the current root password for MariaDB. Press &lt;code&gt;Enter&lt;/code&gt; to continue.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Enter current password for root (enter for none):
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you will be prompted to set a new root password for MariaDB. Enter a new password and press &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Set root password? [Y/n]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be prompted to remove anonymous users. Press &lt;code&gt;Y&lt;/code&gt; and then press &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Remove anonymous users? [Y/n]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be prompted to disable remote root login. Press &lt;code&gt;Y&lt;/code&gt; and then press &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Disallow root login remotely? [Y/n]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be prompted to remove the test database and access to it. Press &lt;code&gt;Y&lt;/code&gt; and then press &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Remove test database and access to it? [Y/n]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be prompted to reload the privilege tables now. Press &lt;code&gt;Y&lt;/code&gt; and then press &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Reload privilege tables now? [Y/n]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3 Configuring PHP to Work with Apache&lt;/h3&gt;
&lt;p&gt;At first, we need to restart Apache.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo systemctl restart httpd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will create a directory for our PHP files.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo mkdir /var/www/html/php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we will create a PHP file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo vi /var/www/html/php/index.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will add the following content to the file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
  phpinfo();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will now open the file in a web browser.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;http://your_domain_name/php/index.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see the following output:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0013-how-to-install-php-and-mariadb-on-amazon-linux-2/phpinfo.png&quot; alt=&quot;phpinfo&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Step 4 Configuring MariaDB to Work with PHP&lt;/h3&gt;
&lt;p&gt;At first, we will create a database for our PHP files.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo mysql -u root -p
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE DATABASE php;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we will create a user for our PHP files.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE USER &amp;#39;php&amp;#39;@&amp;#39;localhost&amp;#39; IDENTIFIED BY &amp;#39;password&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will grant all privileges to the user.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;GRANT ALL PRIVILEGES ON php.* TO &amp;#39;php&amp;#39;@&amp;#39;localhost&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will now exit MariaDB.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will create a PHP file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo vi /var/www/html/php/db.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will add the following content to the file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
  $db = new mysqli(&amp;#39;localhost&amp;#39;, &amp;#39;php&amp;#39;, &amp;#39;password&amp;#39;, &amp;#39;php&amp;#39;);
  if ($db-&amp;gt;connect_error) {
    die(&amp;#39;Connection failed: &amp;#39; . $db-&amp;gt;connect_error);
  }
  echo &amp;#39;Connected successfully&amp;#39;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will now open the file in a web browser.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;http://your_domain_name/php/db.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see the following output:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0013-how-to-install-php-and-mariadb-on-amazon-linux-2/phpdb.png&quot; alt=&quot;phpdb&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to set up PHP and MariaDB on Amazon Linux 2. We also learned how to set up PHP so that it functions with the Apache web server. We also learned how to set up MariaDB so that it functions with PHP.&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/install.unix.php&quot;&gt;PHP Manual - Installation on Unix systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mariadb.com/kb/en/installing-mariadb-packages-with-yum/&quot;&gt;MariaDB Server Documentation - Installing MariaDB Packages with YUM/DNF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html&quot;&gt;Tutorial: Installing a LAMP Web Server on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/amazon-linux-2/faqs/#Amazon_Linux_Extras&quot;&gt;Amazon Linux Extras&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/docs/&quot;&gt;Apache HTTP Server Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mariadb.com/kb/en/mysql_secure_installation/&quot;&gt;&lt;code&gt;mysql_secure_installation&lt;/code&gt; - MariaDB Knowledge Base&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/function.phpinfo.php&quot;&gt;PHP Manual - &lt;code&gt;phpinfo()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/mysqli.construct.php&quot;&gt;PHP Manual - MySQLi connect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/how-to-install-apache-web-server-on-amazon-linux-2&quot;&gt;Previous Post: How to Install Apache Web Server on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/create-database.html&quot;&gt;MySQL CREATE DATABASE Statement&lt;/a&gt; (MariaDB syntax is similar)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/create-user.html&quot;&gt;MySQL CREATE USER Statement&lt;/a&gt; (MariaDB syntax is similar)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/grant.html&quot;&gt;MySQL GRANT Statement&lt;/a&gt; (MariaDB syntax is similar)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>EC2</category><category>PHP</category><category>MariaDB</category><category>Apache</category><category>LAMP Stack</category><category>Linux</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0013-how-to-install-php-and-mariadb-on-amazon-linux-2/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Install Apache Web Server on Amazon Linux 2</title><link>https://mkabumattar.com/blog/post/how-to-install-apache-web-server-on-amazon-linux-2/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-install-apache-web-server-on-amazon-linux-2/</guid><description>We will learn how to install and setup FireWall on Amazon Linux 2 in this tutorial. We will also discover how to set up FireWall so that it functions with the Amazon Linux 2.</description><pubDate>Mon, 24 Oct 2022 00:01:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this tutorial, we will learn how to install Apache web server on Amazon Linux 2. We will also learn how to configure Apache web server to run simple HTML web page.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Amazon Linux 2 EC2 instance.&lt;/li&gt;
&lt;li&gt;A user with sudo privileges.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Install Apache Web Server and run simple HTML web page&lt;/h2&gt;
&lt;h3&gt;Step 1: Install Apache Web Server&lt;/h3&gt;
&lt;p&gt;Before we start, we need to update the package list and upgrade the installed packages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo yum update -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can install Apache web server:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo yum install httpd -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Start Apache Web Server&lt;/h3&gt;
&lt;p&gt;Now, we can start Apache web server:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start Apache Server&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo systemctl start httpd
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Configure Apache to run on system boot&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo systemctl enable httpd
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Configure Firewall&lt;/h3&gt;
&lt;p&gt;Now, we need to configure the firewall to allow HTTP traffic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Create a Simple HTML Web Page&lt;/h3&gt;
&lt;p&gt;Before we can test Apache web server, we need to change the permissions of the &lt;code&gt;/var/www/html&lt;/code&gt; directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo chmod 777 /var/www/html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can create a simple HTML web page:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo vi /var/www/html/index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Apache Web Server&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Apache Web Server&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;This is a simple HTML web page.&amp;lt;/p&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 5: Test Apache Web Server&lt;/h3&gt;
&lt;p&gt;Now, we can test Apache web server by opening the public IP address of our Amazon Linux 2 EC2 instance in a web browser:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0012-how-to-install-apache-web-server-on-amazon-linux-2/apache-web-server.png&quot; alt=&quot;Apache Web Server&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to install Apache web server on Amazon Linux 2. We also learned how to configure Apache web server to run simple HTML web page.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/docs/&quot;&gt;Apache HTTP Server Project Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html&quot;&gt;Tutorial: Installing a LAMP Web Server on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://firewalld.org/documentation/&quot;&gt;Firewalld Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/managing-software.html&quot;&gt;Managing software on your Linux instance - AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/sect-managing_services_with_systemd-services&quot;&gt;Controlling Services with systemctl - Red Hat&lt;/a&gt; (Amazon Linux is RHEL-based)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.fedoraproject.org/en-US/quick-docs/firewalld/&quot;&gt;Using firewalld - Fedora Project Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/amazon-linux-2/&quot;&gt;AWS - Amazon Linux 2 AMI Information&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/post/how-to-install-and-setup-firewall-on-amazon-linux-2&quot;&gt;Previous Post: How to Install and Setup FireWall on Amazon Linux 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/html/&quot;&gt;HTML Tutorial - W3Schools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vim.org/docs.php&quot;&gt;Vi Text Editor Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>EC2</category><category>Apache</category><category>Web Server</category><category>Linux</category><category>Firewall</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0012-how-to-install-apache-web-server-on-amazon-linux-2/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How to Install and Setup FireWall on Amazon Linux 2</title><link>https://mkabumattar.com/blog/post/how-to-install-and-setup-firewall-on-amazon-linux-2/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-install-and-setup-firewall-on-amazon-linux-2/</guid><description>We will learn how to install and setup FireWall on Amazon Linux 2 in this tutorial. We will also discover how to set up FireWall so that it functions with the Amazon Linux 2.</description><pubDate>Mon, 24 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;We will learn how to install and setup FireWall on Amazon Linux 2 in this tutorial. We will also discover how to set up FireWall so that it functions with the Amazon Linux 2.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow along with this tutorial, you will need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Amazon Linux 2 EC2 instance with a public IP address.&lt;/li&gt;
&lt;li&gt;A user with sudo privileges.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Install and Setup Firewalld on Amazon Linux 2&lt;/h2&gt;
&lt;h3&gt;Step 1: Install Firewalld&lt;/h3&gt;
&lt;p&gt;Before we can install FireWall, we must first update the system.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Update the system
sudo yum update -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that the system has been updated, we can install FireWall.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Install FireWall
sudo yum install firewalld -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, after installing FireWall, it&amp;#39;s time to verify whether the &lt;em&gt;iptables&lt;/em&gt; service is running.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Check if the iptables service is running
sudo systemctl status iptables
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the &lt;em&gt;iptables&lt;/em&gt; service is running, we need to stop it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Stop the iptables service
sudo systemctl stop iptables
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that the &lt;em&gt;iptables&lt;/em&gt; service is stopped, we can start the FireWall service.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Start the FireWall service
sudo systemctl start firewalld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To verify that the FireWall service is running, we can use the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Check if the FireWall service is running
sudo systemctl status firewalld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Newly installed FireWall services are not enabled by default. To enable the FireWall service, we can use the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable the FireWall service
sudo systemctl enable firewalld
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Configure Firewalld&lt;/h3&gt;
&lt;p&gt;Now that the FireWall service is running, we can configure it. To configure the FireWall service, we can use the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Configure the FireWall service
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --permanent --zone=public --add-service=ssh
sudo firewall-cmd --reload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;List Firewalld Zones&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# List Firewalld Zones
sudo firewall-cmd --get-zones
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;List Services Default Zone&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# List Services Default Zone
sudo firewall-cmd --get-services
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To verify that the FireWall service is configured correctly, we can use the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Check the FireWall service configuration
sudo firewall-cmd --list-all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;List All Firewalld Zones&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# List All Firewalld Zones
sudo firewall-cmd --list-all-zones
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Set Up Default Firewalld Zone&lt;/h3&gt;
&lt;p&gt;To set up the default Firewalld zone, we can use the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Set up the default Firewalld zone
sudo firewall-cmd --set-default-zone=public
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Check FireWall Status&lt;/h3&gt;
&lt;p&gt;To check the FireWall status, we can use the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Check the FireWall status
sudo firewall-cmd --state
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 5: Assigning Services to Firewalld Zones&lt;/h3&gt;
&lt;p&gt;To assign services to Firewalld zones, we can use the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Assign services to Firewalld zones
firewall-cmd --state
firewall-cmd --get-active-zones
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 6: Adding Services to Firewalld Zones&lt;/h3&gt;
&lt;p&gt;To add services to Firewalld zones, we can use the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add services to Firewalld zones
firewall-cmd --add-service=rtmp

# Remove services from Firewalld zones
firewall-cmd --zone=public --remove-service=rtmp

# add port to zone
firewall-cmd --zone=public --add-port=80/tcp --permanent

# remove port from zone
firewall-cmd --zone=public --remove-port=80/tcp --permanent
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to install and setup FireWall on Amazon Linux 2. We also learned how to set up FireWall so that it functions with the Amazon Linux 2.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://firewalld.org/&quot;&gt;Firewalld Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://firewalld.org/documentation/man-pages/firewalld.html&quot;&gt;Firewalld Documentation - Introduction to firewalld&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://firewalld.org/documentation/man-pages/firewall-cmd.html&quot;&gt;Firewalld Documentation - firewall-cmd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html&quot;&gt;Amazon EC2 User Guide for Linux Instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html&quot;&gt;Security Groups for your VPC - AWS Documentation&lt;/a&gt; (Note: AWS Security Groups act as a primary firewall)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/managing-software.html&quot;&gt;Managing software on your Linux instance - AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/sect-managing_services_with_systemd-services&quot;&gt;Controlling Services with systemctl - Red Hat&lt;/a&gt; (Amazon Linux is RHEL-based)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.fedoraproject.org/en-US/quick-docs/firewalld/&quot;&gt;Using firewalld - Fedora Project Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-using-firewalld-on-centos-7#understanding-firewalld-zones&quot;&gt;Understanding Firewalld Zones - DigitalOcean&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/amazon-linux-2/&quot;&gt;AWS - Amazon Linux 2 AMI Information&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.netfilter.org/documentation/HOWTO//packet-filtering-HOWTO.html&quot;&gt;iptables Tutorial - Netfilter project&lt;/a&gt; (For context, as firewalld is a frontend for netfilter)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>EC2</category><category>Linux</category><category>Firewall</category><category>Security</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0011-how-to-install-and-setup-firewall-on-amazon-linux-2/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Customization Windows Terminal With Starship</title><link>https://mkabumattar.com/blog/post/customization-windows-terminal-with-starship/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/customization-windows-terminal-with-starship/</guid><description>Customization Windows Terminal With Starship, Windows Terminal is a new, modern, fast, efficient, powerful, and productive terminal application for users of command-line tools and shells like Command Prompt, PowerShell, and WSL.</description><pubDate>Fri, 21 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this article, we will learn how to install PowerShell and Starship, how to configure the Windows Terminal, and how to customize the Windows Terminal with Starship.&lt;/p&gt;
&lt;h3&gt;What Is a Windows Terminal?&lt;/h3&gt;
&lt;p&gt;Windows Terminal is a new, modern, fast, efficient, powerful, and productive terminal application for users of command-line tools and shells like Command Prompt, PowerShell, and WSL. It includes many features that make it a great tool for developers and system administrators. It is a great replacement for the default Windows Command Prompt and PowerShell.&lt;/p&gt;
&lt;h3&gt;What Is a Starship?&lt;/h3&gt;
&lt;p&gt;Starship is a cross-shell prompt for any shell. It shows information about the current directory, the active branch, the status of the repository, and much more. It is highly customizable and can be extended with custom modules. It is written in Rust and is blazingly fast.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;h3&gt;Install Windows Terminal&lt;/h3&gt;
&lt;p&gt;To install Windows Terminal, you can download it from the Microsoft Store or from the GitHub repository, or you can use the Chocolatey package manager or Winget package manager.&lt;/p&gt;
&lt;h4&gt;Install Windows Terminal From Microsoft Store&lt;/h4&gt;
&lt;p&gt;To install Windows Terminal from the Microsoft Store, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Microsoft Store.&lt;/li&gt;
&lt;li&gt;Search for Windows Terminal.&lt;/li&gt;
&lt;li&gt;Click on the Get button.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Install Windows Terminal From GitHub&lt;/h4&gt;
&lt;p&gt;To install Windows Terminal from GitHub, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;a href=&quot;https://github.com/microsoft/terminal&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on the Releases tab.&lt;/li&gt;
&lt;li&gt;Click on the latest release.&lt;/li&gt;
&lt;li&gt;Click on the WindowsTerminal.exe file.&lt;/li&gt;
&lt;li&gt;Click on the Download button.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Install Windows Terminal With Chocolatey&lt;/h4&gt;
&lt;p&gt;To install Windows Terminal with Chocolatey, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;a href=&quot;https://chocolatey.org/&quot;&gt;Chocolatey website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on the Packages.&lt;/li&gt;
&lt;li&gt;Search for Windows Terminal.&lt;/li&gt;
&lt;li&gt;Click on the command to install Windows Terminal.&lt;/li&gt;
&lt;li&gt;Run the command in CMD.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;choco install microsoft-windows-terminal --pre -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Install Windows Terminal With Winget&lt;/h4&gt;
&lt;p&gt;To install Windows Terminal with Winget, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;a href=&quot;https://winstall.app/&quot;&gt;Winget website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Search for Windows Terminal.&lt;/li&gt;
&lt;li&gt;Click on the command to install Windows Terminal.&lt;/li&gt;
&lt;li&gt;Run the command in CMD.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;winget install --id=Microsoft.WindowsTerminal  -e
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Install PowerShell&lt;/h3&gt;
&lt;p&gt;To install PowerShell, you can download it from the Microsoft Store or from the GitHub repository, or you can use the Chocolatey package manager or Winget package manager.&lt;/p&gt;
&lt;h4&gt;Install PowerShell From Microsoft Store&lt;/h4&gt;
&lt;p&gt;To install PowerShell from the Microsoft Store, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Microsoft Store.&lt;/li&gt;
&lt;li&gt;Search for PowerShell.&lt;/li&gt;
&lt;li&gt;Click on the Get button.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Install PowerShell From GitHub&lt;/h4&gt;
&lt;p&gt;To install PowerShell from GitHub, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;a href=&quot;https://github.com/PowerShell/PowerShell&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on the Releases tab.&lt;/li&gt;
&lt;li&gt;Click on the latest release.&lt;/li&gt;
&lt;li&gt;Click on the PowerShell-7.2.0-win-x64.msi file.&lt;/li&gt;
&lt;li&gt;Click on the Download button.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Install PowerShell With Chocolatey&lt;/h4&gt;
&lt;p&gt;To install PowerShell with Chocolatey, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;a href=&quot;https://chocolatey.org/&quot;&gt;Chocolatey website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on the Packages.&lt;/li&gt;
&lt;li&gt;Search for PowerShell.&lt;/li&gt;
&lt;li&gt;Click on the command to install PowerShell.&lt;/li&gt;
&lt;li&gt;Run the command in CMD.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;choco install powershell -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Install PowerShell With Winget&lt;/h4&gt;
&lt;p&gt;To install PowerShell with Winget, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;a href=&quot;https://winstall.app/&quot;&gt;Winget website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Search for PowerShell.&lt;/li&gt;
&lt;li&gt;Click on the command to install PowerShell.&lt;/li&gt;
&lt;li&gt;Run the command in CMD.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;winget install --id=Microsoft.PowerShell  -e
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Install Starship&lt;/h3&gt;
&lt;p&gt;To install Starship, you can download it from the GitHub repository, or you can use the Chocolatey package manager or Winget package manager.&lt;/p&gt;
&lt;h4&gt;Install Starship From GitHub&lt;/h4&gt;
&lt;p&gt;To install Starship from GitHub, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;a href=&quot;https://github.com/starship/starship&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on the Releases tab.&lt;/li&gt;
&lt;li&gt;Click on the latest release.&lt;/li&gt;
&lt;li&gt;Click on the starship-x86_64-pc-windows-msvc.zip file.&lt;/li&gt;
&lt;li&gt;Click on the Download button.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Install Starship With Chocolatey&lt;/h4&gt;
&lt;p&gt;To install Starship with Chocolatey, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;a href=&quot;https://chocolatey.org/&quot;&gt;Chocolatey website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on the Packages.&lt;/li&gt;
&lt;li&gt;Search for Starship.&lt;/li&gt;
&lt;li&gt;Click on the command to install Starship.&lt;/li&gt;
&lt;li&gt;Run the command in CMD.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;choco install starship -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Install Starship With Winget&lt;/h4&gt;
&lt;p&gt;To install Starship with Winget, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;a href=&quot;https://winstall.app/&quot;&gt;Winget website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Search for Starship.&lt;/li&gt;
&lt;li&gt;Click on the command to install Starship.&lt;/li&gt;
&lt;li&gt;Run the command in CMD.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;winget install --id=Starship.Starship  -e
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Install Nerd Font&lt;/h3&gt;
&lt;p&gt;Quick install a nerd font from the &lt;a href=&quot;https://www.nerdfonts.com/&quot;&gt;Nerd Fonts website&lt;/a&gt;. You can choose any font you like. I will use the &lt;code&gt;Caskaydia Cove Nerd Font&lt;/code&gt; font.&lt;/p&gt;
&lt;h2&gt;Configuration&lt;/h2&gt;
&lt;h3&gt;Configure Starship&lt;/h3&gt;
&lt;p&gt;To configure Starship, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the powershell.&lt;/li&gt;
&lt;li&gt;Run the command below to create the configuration file.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;mkdir -p ~/.config &amp;amp;&amp;amp; touch ~/.config/starship.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Open the configuration file with your favorite text editor.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;notepad ~/.config/starship.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Copy the configuration below and paste it in the configuration file. &lt;a href=&quot;https://raw.githubusercontent.com/MKAbuMattar/.dotfiles/main/.config/starship.toml&quot;&gt;GitHub | starship.toml&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;# ~/.config/starship.toml
#
#                             .
#         ..                .&amp;#39;&amp;#39;
#         .,&amp;#39;..,.         ..,;,&amp;#39;
#          ,;;;;,,       .,,;;;
#           ,;;;;;&amp;#39;    .&amp;#39;,;;;
#            ,;;;;,&amp;#39;...,;;;,
#             ,;;;;;,,;;;;.
#              ,;;;;;;;;;
#              .,;;;;;;;
#              .,;;;;;;;&amp;#39;
#              .,;;;;;;;,&amp;#39;
#            .&amp;#39;,;;;;;;;;;;,.
#          ..,;;;;;;;;;;;;;,.
#         .&amp;#39;;;;;;.   &amp;#39;;;;;;;,&amp;#39;
#        .,;;;;.      ,; .;; .,
#        &amp;#39;,;;;.        .
#        .,;;.
#        ,;
#
## FIRST LINE/ROW: Info &amp;amp; Status
# First param ─┌
[username]
format = &amp;quot; [╭─$user]($style)@&amp;quot;
show_always = true
style_root = &amp;quot;bold red&amp;quot;
style_user = &amp;quot;bold red&amp;quot;

# Second param
[hostname]
disabled = false
format = &amp;quot;[$hostname]($style) in &amp;quot;
ssh_only = false
style = &amp;quot;bold dimmed red&amp;quot;
trim_at = &amp;quot;-&amp;quot;

# Third param
[directory]
style = &amp;quot;purple&amp;quot;
truncate_to_repo = true
truncation_length = 0
truncation_symbol = &amp;quot;repo: &amp;quot;

# Fourth param
[sudo]
disabled = false

# Before all the version info (python, nodejs, php, etc.)
[git_status]
ahead = &amp;quot;⇡${count}&amp;quot;
behind = &amp;quot;⇣${count}&amp;quot;
deleted = &amp;quot;x&amp;quot;
diverged = &amp;quot;⇕⇡${ahead_count}⇣${behind_count}&amp;quot;
style = &amp;quot;white&amp;quot;

# Last param in the first line/row
[cmd_duration]
disabled = false
format = &amp;quot;took [$duration]($style)&amp;quot;
min_time = 1


## SECOND LINE/ROW: Prompt
# Somethere at the beginning
[battery]
charging_symbol = &amp;quot;&amp;quot;
disabled = true
discharging_symbol = &amp;quot;&amp;quot;
full_symbol = &amp;quot;&amp;quot;

[[battery.display]]  # &amp;quot;bold red&amp;quot; style when capacity is between 0% and 10%
disabled = false
style = &amp;quot;bold red&amp;quot;
threshold = 15

[[battery.display]]  # &amp;quot;bold yellow&amp;quot; style when capacity is between 10% and 30%
disabled = true
style = &amp;quot;bold yellow&amp;quot;
threshold = 50

[[battery.display]]  # &amp;quot;bold green&amp;quot; style when capacity is between 10% and 30%
disabled = true
style = &amp;quot;bold green&amp;quot;
threshold = 80

# Prompt: optional param 1
[time]
disabled = true
format = &amp;quot; 🕙 $time($style)\n&amp;quot;
style = &amp;quot;bright-white&amp;quot;
time_format = &amp;quot;%T&amp;quot;

# Prompt: param 2
[character]
error_symbol = &amp;quot; [×](bold red)&amp;quot;
success_symbol = &amp;quot; [╰─λ](bold red)&amp;quot;

# SYMBOLS
[status]
disabled = false
format = &amp;#39;[\[$symbol$status_common_meaning$status_signal_name$status_maybe_int\]]($style)&amp;#39;
map_symbol = true
pipestatus = true
symbol = &amp;quot;🔴&amp;quot;

[aws]
symbol = &amp;quot; &amp;quot;

[conda]
symbol = &amp;quot; &amp;quot;

[dart]
symbol = &amp;quot; &amp;quot;

[docker_context]
symbol = &amp;quot; &amp;quot;

[elixir]
symbol = &amp;quot; &amp;quot;

[elm]
symbol = &amp;quot; &amp;quot;

[git_branch]
symbol = &amp;quot; &amp;quot;

[golang]
symbol = &amp;quot; &amp;quot;

[hg_branch]
symbol = &amp;quot; &amp;quot;

[java]
symbol = &amp;quot; &amp;quot;

[julia]
symbol = &amp;quot; &amp;quot;

[nim]
symbol = &amp;quot; &amp;quot;

[nix_shell]
symbol = &amp;quot; &amp;quot;

[nodejs]
symbol = &amp;quot; &amp;quot;

[package]
symbol = &amp;quot; &amp;quot;

[perl]
symbol = &amp;quot; &amp;quot;

[php]
symbol = &amp;quot; &amp;quot;

[python]
symbol = &amp;quot; &amp;quot;

[ruby]
symbol = &amp;quot; &amp;quot;

[rust]
symbol = &amp;quot; &amp;quot;

[swift]
symbol = &amp;quot;ﯣ &amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;Configure Starship on PowerShell&lt;/h3&gt;
&lt;p&gt;Every time a PowerShell instance launches, we&amp;#39;ll need to instance starship, to achieve this, we&amp;#39;ll need to add the following line to our PowerShell profile.&lt;/p&gt;
&lt;p&gt;To create a PowerShell profile, and add the starship instance, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open Windows Terminal.&lt;/li&gt;
&lt;li&gt;Run the following command to create a PowerShell profile.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;New-Item -Path $PROFILE -ItemType File -Force
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Run the following command to &lt;code&gt;Set-Content&lt;/code&gt; cmdlet to add the line to the profile.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$CONFIG_PROFILE = {function Invoke-Starship-TransientFunction {
  &amp;amp;starship module character
}

Invoke-Expression (&amp;amp;starship init powershell)}

Set-Content -Path $PROFILE -Value $CONFIG_PROFILE
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;Notice type=&quot;note&quot;&gt;
  You can check the location of this file by querying the `$PROFILE` variable in
  PowerShell. The path is often
  `~\Documents\PowerShell\Microsoft.PowerShell_profile.ps1`.
&lt;/Notice&gt;&lt;h3&gt;Configure PowerShell on Windows Terminal&lt;/h3&gt;
&lt;p&gt;To configure PowerShell on Windows Terminal, you can follow the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open Windows Terminal.&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Ctrl + ,&lt;/code&gt; to open the settings.&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;settings.json&lt;/code&gt; to open the settings file.&lt;/li&gt;
&lt;li&gt;Add the following lines to the &lt;code&gt;profiles&lt;/code&gt; section.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;guid&amp;quot;: &amp;quot;{574e775e-4f2a-5b96-ac1e-a2962a402336}&amp;quot;,
  &amp;quot;hidden&amp;quot;: false,
  &amp;quot;name&amp;quot;: &amp;quot;PowerShell&amp;quot;,
  &amp;quot;source&amp;quot;: &amp;quot;Windows.Terminal.PowershellCore&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Change the &lt;code&gt;hidden&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt; for the &lt;code&gt;Windows PowerShell&lt;/code&gt; profile.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;commandline&amp;quot;: &amp;quot;%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe&amp;quot;,
  &amp;quot;guid&amp;quot;: &amp;quot;{61c54bbd-c2c6-5271-96e7-009a87ff44bf}&amp;quot;,
  &amp;quot;hidden&amp;quot;: true,
  &amp;quot;name&amp;quot;: &amp;quot;Windows PowerShell&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Add &lt;code&gt;Dracula schemes&lt;/code&gt; to the &lt;code&gt;schemes&lt;/code&gt; section.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;background&amp;quot;: &amp;quot;#282A36&amp;quot;,
  &amp;quot;black&amp;quot;: &amp;quot;#21222C&amp;quot;,
  &amp;quot;blue&amp;quot;: &amp;quot;#BD93F9&amp;quot;,
  &amp;quot;brightBlack&amp;quot;: &amp;quot;#6272A4&amp;quot;,
  &amp;quot;brightBlue&amp;quot;: &amp;quot;#D6ACFF&amp;quot;,
  &amp;quot;brightCyan&amp;quot;: &amp;quot;#A4FFFF&amp;quot;,
  &amp;quot;brightGreen&amp;quot;: &amp;quot;#69FF94&amp;quot;,
  &amp;quot;brightPurple&amp;quot;: &amp;quot;#FF92DF&amp;quot;,
  &amp;quot;brightRed&amp;quot;: &amp;quot;#FF6E6E&amp;quot;,
  &amp;quot;brightWhite&amp;quot;: &amp;quot;#FFFFFF&amp;quot;,
  &amp;quot;brightYellow&amp;quot;: &amp;quot;#FFFFA5&amp;quot;,
  &amp;quot;cursorColor&amp;quot;: &amp;quot;#F8F8F2&amp;quot;,
  &amp;quot;cyan&amp;quot;: &amp;quot;#8BE9FD&amp;quot;,
  &amp;quot;foreground&amp;quot;: &amp;quot;#F8F8F2&amp;quot;,
  &amp;quot;green&amp;quot;: &amp;quot;#50FA7B&amp;quot;,
  &amp;quot;name&amp;quot;: &amp;quot;Dracula&amp;quot;,
  &amp;quot;purple&amp;quot;: &amp;quot;#FF79C6&amp;quot;,
  &amp;quot;red&amp;quot;: &amp;quot;#FF5555&amp;quot;,
  &amp;quot;selectionBackground&amp;quot;: &amp;quot;#44475A&amp;quot;,
  &amp;quot;white&amp;quot;: &amp;quot;#F8F8F2&amp;quot;,
  &amp;quot;yellow&amp;quot;: &amp;quot;#F1FA8C&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Save the file and close it.&lt;/li&gt;
&lt;li&gt;Back to Windows Terminal, click on &lt;code&gt;Ctrl + ,&lt;/code&gt; to open the settings.&lt;/li&gt;
&lt;li&gt;Go to Profiles &amp;gt;&amp;gt; Defaults &amp;gt;&amp;gt; Appearance &amp;gt;&amp;gt; Color scheme choose &lt;code&gt;Dracula&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go to Profiles &amp;gt;&amp;gt; Defaults &amp;gt;&amp;gt; Appearance &amp;gt;&amp;gt; Font face choose &lt;code&gt;Caskaydia Cove Nerd Font&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0009-customization-windows-terminal-with-starship/2022-10-21-183905.png&quot; alt=&quot;Settings&quot;&gt;&lt;/p&gt;
&lt;h4&gt;Extra Configuration&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Open Windows Terminal.&lt;/li&gt;
&lt;li&gt;Run the command&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# Allow scripts to run
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

# Install PSReadLine
Install-Module PSReadLine -AllowPrerelease -Force

# Install Terminal-Icons
Install-Module Terminal-Icons -AllowPrerelease -Force
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Run the following command to &lt;code&gt;Set-Content&lt;/code&gt; cmdlet to add the line to the profile.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$CONFIG_PROFILE = {function Invoke-Starship-TransientFunction {
  &amp;amp;starship module character
}

Invoke-Expression (&amp;amp;starship init powershell)

# set PowerShell to UTF-8
[console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding

Import-Module -Name Terminal-Icons

Set-PSReadLineOption -PredictionViewStyle ListView
Set-PSReadLineOption -PredictionViewStyle InlineView

Set-PSReadLineOption -EditMode WindowS

Set-PSReadLineKeyHandler -Chord Ctrl+B -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert(&amp;#39;build&amp;#39;)
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
}


# This is an example of a macro that you might use to execute a command.
# This will add the command to history.
Set-PSReadLineKeyHandler -Key Ctrl+Shift+b `
                         -BriefDescription BuildCurrentDirectory `
                         -LongDescription &amp;quot;Build the current directory&amp;quot; `
                         -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert(&amp;quot;dotnet build&amp;quot;)
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
}}

Set-Content -Path $PROFILE -Value $CONFIG_PROFILE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blog/0009-customization-windows-terminal-with-starship/2022-10-21-184138.png&quot; alt=&quot;Settings&quot;&gt;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://starship.rs/&quot;&gt;Starship - The minimal, blazing-fast, and infinitely customizable prompt for any shell!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://starship.rs/config/&quot;&gt;Starship Configuration Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/terminal/&quot;&gt;Windows Terminal Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/terminal&quot;&gt;Windows Terminal GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/&quot;&gt;PowerShell Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShell&quot;&gt;PowerShell GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nerdfonts.com/&quot;&gt;Nerd Fonts - Iconic font aggregator, glyphs patcher, and more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://draculatheme.com/windows-terminal&quot;&gt;Dracula Theme for Windows Terminal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chocolatey.org/&quot;&gt;Chocolatey - The package manager for Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/package-manager/winget/&quot;&gt;Winget - Windows Package Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/PSReadLine/&quot;&gt;PSReadLine Module - PowerShell Gallery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/Terminal-Icons/&quot;&gt;Terminal-Icons Module - PowerShell Gallery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/terminal/customize-settings/global-settings&quot;&gt;Windows Terminal Settings (JSON) file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/MKAbuMattar/.dotfiles/main/.config/starship.toml&quot;&gt;Starship &lt;code&gt;starship.toml&lt;/code&gt; example from the post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Windows</category><category>Terminal</category><category>PowerShell</category><category>Starship</category><category>Customization</category><category>Developer Tools</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0009-customization-windows-terminal-with-starship/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Introduction to Linux CLI</title><link>https://mkabumattar.com/blog/post/introduction-to-linux-cli/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/introduction-to-linux-cli/</guid><description>Introduction to Linux command-line interface CLI, Linux is a Unix-like computer operating system assembled under the model of free and open-source software development and distribution.</description><pubDate>Wed, 19 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The Linux operating system family is a group of free and open-source Unix systems. They consist of Red Hat, Arch Linux, Ubuntu, Debian, openSUSE, and Fedora. You must utilize a shell when using Linux, an application that allows you access to the system&amp;#39;s features. The majority of Linux distributions have a graphical user interface (GUI), which makes them user-friendly for beginners. I advise using the command-line interface (CLI), as it is speedier and gives you more control. By putting commands into the CLI, tasks that take many steps on the GUI may be completed in a matter of seconds.&lt;/p&gt;
&lt;h2&gt;What Is a Linux Command?&lt;/h2&gt;
&lt;p&gt;An application or tool that runs on the CLI, a console that communicates with the system via text and processes, is known as a Linux command. It resembles Windows&amp;#39; Command Prompt program in many ways. By hitting Enter at the end of the line, Linux commands are run on the terminal. You may use commands to carry out a range of operations, including managing users, installing packages, and manipulating files.&lt;/p&gt;
&lt;p&gt;The general syntax of a Linux command is as follows:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CommandName [flag(s)] [parameter(s)]&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CommandName&lt;/strong&gt; is the name of the command you want to run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flag(s)&lt;/strong&gt; are optional arguments that modify the behavior of the command.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parameter(s)&lt;/strong&gt; are required arguments that specify the command&amp;#39;s input.&lt;/li&gt;
&lt;/ul&gt;
&lt;Notice type=&quot;note&quot;&gt;
  Remember that case affects the syntax of every Linux command.
&lt;/Notice&gt;&lt;h2&gt;File Management&lt;/h2&gt;
&lt;p&gt;Every system administrator should be familiar with the very basic commands listed in this section. This collection of Linux commands for managing files is undoubtedly incomplete, but it can serve as a starting point and cover the majority of simple to complicated situations.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;pwd&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;pwd&lt;/code&gt; command is used to print the current working directory. The working directory is the directory you are currently in. The output of the &lt;code&gt;pwd&lt;/code&gt; command is the path to the working directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Print the current working directory
pwd
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;pwd&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-L&lt;/code&gt; - If the current working directory is a symbolic link, print the path of the symbolic link.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-P&lt;/code&gt; - If the current working directory is a symbolic link, print the path of the symbolic link&amp;#39;s target.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Print the current working directory
pwd -L

# Print the current working directory
pwd -P
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;ls&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ls&lt;/code&gt; is A system&amp;#39;s files and directories are listed using the &lt;code&gt;ls&lt;/code&gt; command. It will display the contents of the current working directory when run without a flag or argument.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# List the contents of the current working directory
ls
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;ls&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - List all files, including hidden files.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - List files in long format.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - List files in human-readable format.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - List files in reverse order.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - List files by the time they were last modified.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# List all files, including hidden files
ls -a

# List files in long format
ls -l

# List files in human-readable format
ls -h

# List files in reverse order
ls -r

# List files by the time they were last modified
ls -t
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;cd&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;cd&lt;/code&gt; command is used to change the current working directory. It takes a directory as an argument. The output of the &lt;code&gt;cd&lt;/code&gt; command is the new working directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the current working directory to the home directory
cd ~
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;mkdir&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;mkdir&lt;/code&gt; command is used to create a new directory. It takes a directory name as an argument. The output of the &lt;code&gt;mkdir&lt;/code&gt; command is the newly created directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a new directory named &amp;quot;new-directory&amp;quot;
mkdir new-directory
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;mkdir&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Create parent directories as needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a new directory named &amp;quot;new-directory&amp;quot; and its parent directories
mkdir -p new-directory
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;touch&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;touch&lt;/code&gt; command is used to create a new file. It takes a file name as an argument. The output of the &lt;code&gt;touch&lt;/code&gt; command is the newly created file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a new file named &amp;quot;new-file&amp;quot;
touch new-file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;touch&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Change the access time of the file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Change the modification time of the file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Change the access and modification times of the file.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the access time of the file
touch -a new-file

# Change the modification time of the file
touch -m new-file

# Change the access and modification times of the file
touch -t new-file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;cp&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;cp&lt;/code&gt; command is used to copy files and directories. It takes the source and destination as arguments. The output of the &lt;code&gt;cp&lt;/code&gt; command is the copied file or directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Copy the file &amp;quot;file&amp;quot; to the directory &amp;quot;directory&amp;quot;
cp file directory
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;cp&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Copy directories recursively.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Copy the directory &amp;quot;directory&amp;quot; to the directory &amp;quot;new-directory&amp;quot;
cp -r directory new-directory
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;mv&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;mv&lt;/code&gt; command is used to move files and directories. It takes the source and destination as arguments. The output of the &lt;code&gt;mv&lt;/code&gt; command is the moved file or directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Move the file &amp;quot;file&amp;quot; to the directory &amp;quot;directory&amp;quot;
mv file directory
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;mv&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Prompt before overwriting an existing file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Force the move of a file, even if it already exists.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Move a file only if the source file is newer than the destination file.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Move the file &amp;quot;file&amp;quot; to the directory &amp;quot;directory&amp;quot; and prompt before overwriting an existing file
mv -i file directory

# Move the file &amp;quot;file&amp;quot; to the directory &amp;quot;directory&amp;quot; and force the move of a file, even if it already exists
mv -f file directory

# Move the file &amp;quot;file&amp;quot; to the directory &amp;quot;directory&amp;quot; and move a file only if the source file is newer than the destination file
mv -u file directory
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;rm&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;rm&lt;/code&gt; command is used to remove files and directories. It takes the file or directory as an argument. The output of the &lt;code&gt;rm&lt;/code&gt; command is the removed file or directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Remove the file &amp;quot;file&amp;quot;
rm file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;rm&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Remove directories and their contents recursively.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Force remove files without prompting for confirmation.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Remove the directory &amp;quot;directory&amp;quot; and its contents recursively
rm -r directory

# Remove the file &amp;quot;file&amp;quot; without prompting for confirmation
rm -f file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;rmdir&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;rmdir&lt;/code&gt; command is used to remove empty directories. It takes the directory as an argument. The output of the &lt;code&gt;rmdir&lt;/code&gt; command is the removed directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Remove the directory &amp;quot;directory&amp;quot;
rmdir directory
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;rmdir&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Remove parent directories as needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Remove the directory &amp;quot;directory&amp;quot; and its parent directories
rmdir -p directory
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;cat&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;cat&lt;/code&gt; command is used to display the contents of a file. It takes a file as an argument. The output of the &lt;code&gt;cat&lt;/code&gt; command is the contents of the specified file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the contents of the file &amp;quot;file&amp;quot;
cat file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;cat&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Number all output lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the contents of the file &amp;quot;file&amp;quot; and number all output lines
cat -n file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;more&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;more&lt;/code&gt; command is used to display the contents of a file. It takes a file as an argument. The output of the &lt;code&gt;more&lt;/code&gt; command is the contents of the specified file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the contents of the file &amp;quot;file&amp;quot;
more file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;more&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Display the contents of the file &amp;quot;file&amp;quot; and number all output lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the contents of the file &amp;quot;file&amp;quot; and number all output lines
more -d file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;less&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;less&lt;/code&gt; command is used to display the contents of a file. It takes a file as an argument. The output of the &lt;code&gt;less&lt;/code&gt; command is the contents of the specified file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the contents of the file &amp;quot;file&amp;quot;
less file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;less&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-N&lt;/code&gt; - Display the contents of the file &amp;quot;file&amp;quot; and number all output lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the contents of the file &amp;quot;file&amp;quot; and number all output lines
less -N file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;head&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;head&lt;/code&gt; command is used to display the first 10 lines of a file. It takes a file as an argument. The output of the &lt;code&gt;head&lt;/code&gt; command is the first 10 lines of the specified file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the first 10 lines of the file &amp;quot;file&amp;quot;
head file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;head&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Display the first n lines of the file &amp;quot;file&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the first 5 lines of the file &amp;quot;file&amp;quot;
head -n 5 file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;tail&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;tail&lt;/code&gt; command is used to display the last 10 lines of a file. It takes a file as an argument. The output of the &lt;code&gt;tail&lt;/code&gt; command is the last 10 lines of the specified file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the last 10 lines of the file &amp;quot;file&amp;quot;
tail file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;tail&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Display the last n lines of the file &amp;quot;file&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the last 5 lines of the file &amp;quot;file&amp;quot;
tail -n 5 file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h2&gt;Finding files and directories&lt;/h2&gt;
&lt;p&gt;The find command will be used the majority of the time to locate files and folders. But I also enjoy the which command since it provides the binary&amp;#39;s path, which is necessary on several occasions when we must run a binary with a complete PATH.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;find&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;find&lt;/code&gt; command is used to find files and directories. It takes a directory as an argument. The output of the &lt;code&gt;find&lt;/code&gt; command is the files and directories that match the specified criteria.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Find all files and directories in the current directory
find .
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;find&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-name&lt;/code&gt; - Find files and directories with the specified name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-type&lt;/code&gt; - Find files and directories of the specified type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-size&lt;/code&gt; - Find files and directories of the specified size.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-mtime&lt;/code&gt; - Find files and directories that have been modified in the specified number of days.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-exec&lt;/code&gt; - Execute the specified command on the found files and directories.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Find all files and directories in the current directory with the name &amp;quot;file&amp;quot;
find . -name file

# Find all files and directories in the current directory of the type &amp;quot;file&amp;quot;
find . -type file

# Find all files and directories in the current directory of the size &amp;quot;1M&amp;quot;
find . -size 1M

# Find all files and directories in the current directory that have been modified in the last 5 days
find . -mtime 5

# Find all files and directories in the current directory with the name &amp;quot;file&amp;quot; and execute the command &amp;quot;ls&amp;quot; on them
find . -name file -exec ls {} \;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;locate&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;locate&lt;/code&gt; command is used to find files and directories. It takes a file or directory name as an argument. The output of the &lt;code&gt;locate&lt;/code&gt; command is the files and directories that match the specified criteria.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Find all files and directories in the current directory with the name &amp;quot;file&amp;quot;
locate file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;locate&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Find files and directories with the specified name, ignoring case.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Find all files and directories in the current directory with the name &amp;quot;file&amp;quot; ignoring case
locate -i file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;which&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;which&lt;/code&gt; command is used to find the location of a command. It takes a command as an argument. The output of the &lt;code&gt;which&lt;/code&gt; command is the location of the specified command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Find the location of the command &amp;quot;command&amp;quot;
which command
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;which&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Find all locations of the specified command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Find the location of the specified command and return a status code of 0 if the command is found and 1 if the command is not found.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Find all locations of the command &amp;quot;command&amp;quot;
which -a command

# Find the location of the command &amp;quot;command&amp;quot; and return a status code of 0 if the command is found and 1 if the command is not found
which -s command
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;whereis&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;whereis&lt;/code&gt; command is used to find the location of a command. It takes a command as an argument. The output of the &lt;code&gt;whereis&lt;/code&gt; command is the location of the specified command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Find the location of the command &amp;quot;command&amp;quot;
whereis command
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;whereis&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Find the location of the specified command and return a status code of 0 if the command is found and 1 if the command is not found.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Find the location of the command &amp;quot;command&amp;quot; and return a status code of 0 if the command is found and 1 if the command is not found
whereis -b command
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h2&gt;Check User Information&lt;/h2&gt;
&lt;p&gt;These are a few of the commands we employ to verify the details of the most recent person to log in, as well as a few others to obtain further information regarding an existing user.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;whoami&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;whoami&lt;/code&gt; command is used to display the current user. It takes no arguments. The output of the &lt;code&gt;whoami&lt;/code&gt; command is the current user.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the current user
whoami
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;whoami&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Display the current user and return a status code of 0 if the user is found and 1 if the user is not found.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the current user and return a status code of 0 if the user is found and 1 if the user is not found
whoami -u
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;who&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;who&lt;/code&gt; command is used to display the current users. It takes no arguments. The output of the &lt;code&gt;who&lt;/code&gt; command is the current users.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the current users
who
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;who&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Display the current users and return a status code of 0 if the users are found and 1 if the users are not found.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the current users and return a status code of 0 if the users are found and 1 if the users are not found
who -u
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;w&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;w&lt;/code&gt; command is used to display the current users. It takes no arguments. The output of the &lt;code&gt;w&lt;/code&gt; command is the current users.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the current users
w
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;w&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Display the current users and return a status code of 0 if the users are found and 1 if the users are not found.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the current users and return a status code of 0 if the users are found and 1 if the users are not found
w -u
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;id&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; command is used to display the current user. It takes no arguments. The output of the &lt;code&gt;id&lt;/code&gt; command is the current user.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the current user
id
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;id&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Display the current user and return a status code of 0 if the user is found and 1 if the user is not found.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the current user and return a status code of 0 if the user is found and 1 if the user is not found
id -u
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;groups&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;groups&lt;/code&gt; command is used to display the current user&amp;#39;s groups. It takes no arguments. The output of the &lt;code&gt;groups&lt;/code&gt; command is the current user&amp;#39;s groups.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the current user&amp;#39;s groups
groups
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Managing Users and Groups&lt;/h2&gt;
&lt;p&gt;These are some of the fundamental Linux commands for managing users, including adding, editing, and removing individuals or groups.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;useradd&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;useradd&lt;/code&gt; command is used to add a user. It takes a username as an argument. The output of the &lt;code&gt;useradd&lt;/code&gt; command is the user that was added.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add a user with the username &amp;quot;user&amp;quot;
useradd user
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;useradd&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Add a user with the specified comment.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Add a user with the specified home directory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-g&lt;/code&gt; - Add a user with the specified primary group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-G&lt;/code&gt; - Add a user with the specified supplementary groups.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Add a user with the specified home directory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Add a user with the specified shell.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Add a user with the specified user ID.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add a user with the username &amp;quot;user&amp;quot; and comment &amp;quot;comment&amp;quot;
useradd -c &amp;quot;comment&amp;quot; user

# Add a user with the username &amp;quot;user&amp;quot; and home directory &amp;quot;/home/user&amp;quot;
useradd -d /home/user user

# Add a user with the username &amp;quot;user&amp;quot; and primary group &amp;quot;group&amp;quot;
useradd -g group user

# Add a user with the username &amp;quot;user&amp;quot; and supplementary groups &amp;quot;group1&amp;quot;, &amp;quot;group2&amp;quot;, and &amp;quot;group3&amp;quot;
useradd -G group1,group2,group3 user

# Add a user with the username &amp;quot;user&amp;quot; and home directory &amp;quot;/home/user&amp;quot;
useradd -m /home/user user

# Add a user with the username &amp;quot;user&amp;quot; and shell &amp;quot;/bin/sh&amp;quot;
useradd -s /bin/sh user

# Add a user with the username &amp;quot;user&amp;quot; and user ID &amp;quot;1000&amp;quot;
useradd -u 1000 user
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;userdel&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;userdel&lt;/code&gt; command is used to delete a user. It takes a username as an argument. The output of the &lt;code&gt;userdel&lt;/code&gt; command is the user that was deleted.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Delete a user with the username &amp;quot;user&amp;quot;
userdel user
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;userdel&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Delete a user with the specified home directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Delete a user with the username &amp;quot;user&amp;quot; and home directory &amp;quot;/home/user&amp;quot;
userdel -r /home/user user
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;usermod&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;usermod&lt;/code&gt; command is used to modify a user. It takes a username as an argument. The output of the &lt;code&gt;usermod&lt;/code&gt; command is the user that was modified.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Modify a user with the username &amp;quot;user&amp;quot;
usermod user
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;usermod&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Modify a user with the specified comment.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Modify a user with the specified home directory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; - Modify a user with the specified expiration date.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-g&lt;/code&gt; - Modify a user with the specified primary group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-G&lt;/code&gt; - Modify a user with the specified supplementary groups.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Modify a user with the specified username.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Modify a user with the specified home directory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Modify a user with the specified shell.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Modify a user with the specified user ID.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Modify a user with the username &amp;quot;user&amp;quot; and comment &amp;quot;comment&amp;quot;
usermod -c &amp;quot;comment&amp;quot; user

# Modify a user with the username &amp;quot;user&amp;quot; and home directory &amp;quot;/home/user&amp;quot;
usermod -d /home/user user

# Modify a user with the username &amp;quot;user&amp;quot; and expiration date &amp;quot;2023-01-01&amp;quot;
usermod -e 2023-01-01 user

# Modify a user with the username &amp;quot;user&amp;quot; and primary group &amp;quot;group&amp;quot;
usermod -g group user

# Modify a user with the username &amp;quot;user&amp;quot; and supplementary groups &amp;quot;group1&amp;quot;, &amp;quot;group2&amp;quot;, and &amp;quot;group3&amp;quot;
usermod -G group1,group2,group3 user

# Modify a user with the username &amp;quot;user&amp;quot; and username &amp;quot;user2&amp;quot;
usermod -l user2 user

# Modify a user with the username &amp;quot;user&amp;quot; and home directory &amp;quot;/home/user&amp;quot;
usermod -m /home/user user

# Modify a user with the username &amp;quot;user&amp;quot; and shell &amp;quot;/bin/sh&amp;quot;
usermod -s /bin/sh user

# Modify a user with the username &amp;quot;user&amp;quot; and user ID &amp;quot;1000&amp;quot;
usermod -u 1000 user
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;passwd&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;passwd&lt;/code&gt; command is used to change a user&amp;#39;s password. It takes a username as an argument. The output of the &lt;code&gt;passwd&lt;/code&gt; command is the user&amp;#39;s password that was changed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change a user&amp;#39;s password with the username &amp;quot;user&amp;quot;
passwd user
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;passwd&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Change a user&amp;#39;s password with the specified username and delete the password.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; - Change a user&amp;#39;s password with the specified username and expire the password.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Change a user&amp;#39;s password with the specified username and lock the password.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Change a user&amp;#39;s password with the specified username and unlock the password.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change a user&amp;#39;s password with the username &amp;quot;user&amp;quot; and delete the password
passwd -d user

# Change a user&amp;#39;s password with the username &amp;quot;user&amp;quot; and expire the password
passwd -e user

# Change a user&amp;#39;s password with the username &amp;quot;user&amp;quot; and lock the password
passwd -l user

# Change a user&amp;#39;s password with the username &amp;quot;user&amp;quot; and unlock the password
passwd -u user
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;groupadd&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;groupadd&lt;/code&gt; command is used to add a group. It takes a group name as an argument. The output of the &lt;code&gt;groupadd&lt;/code&gt; command is the group that was added.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add a group with the group name &amp;quot;group&amp;quot;
groupadd group
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;groupadd&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-g&lt;/code&gt; - Add a group with the specified group ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Add a group with the specified system group.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Add a group with the specified force.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add a group with the group name &amp;quot;group&amp;quot; and group ID &amp;quot;1000&amp;quot;
groupadd -g 1000 group

# Add a group with the group name &amp;quot;group&amp;quot; and system group
groupadd -r group

# Add a group with the group name &amp;quot;group&amp;quot; and force
groupadd -f group
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;groupdel&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;groupdel&lt;/code&gt; command is used to delete a group. It takes a group name as an argument. The output of the &lt;code&gt;groupdel&lt;/code&gt; command is the group that was deleted.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Delete a group with the group name &amp;quot;group&amp;quot;
groupdel group
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;groupdel&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Delete a group with the specified force.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Delete a group with the group name &amp;quot;group&amp;quot; and force
groupdel -f group
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;groupmod&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;groupmod&lt;/code&gt; command is used to modify a group. It takes a group name as an argument. The output of the &lt;code&gt;groupmod&lt;/code&gt; command is the group that was modified.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Modify a group with the group name &amp;quot;group&amp;quot;
groupmod group
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;groupmod&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-g&lt;/code&gt; - Modify a group with the specified group ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Modify a group with the specified group name.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Modify a group with the group name &amp;quot;group&amp;quot; and group ID &amp;quot;1000&amp;quot;
groupmod -g 1000 group

# Modify a group with the group name &amp;quot;group&amp;quot; and group name &amp;quot;group2&amp;quot;
groupmod -n group2 group
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h2&gt;Managing Permissions&lt;/h2&gt;
&lt;p&gt;I have simply addressed the fundamental commands that we use to assign, change, and remove rights from files and directories because the topic of Linux permissions is rather broad.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;chown&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;chown&lt;/code&gt; command is used to change the owner of a file or directory. It takes a username and a file or directory as arguments. The output of the &lt;code&gt;chown&lt;/code&gt; command is the file or directory that was changed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the owner of a file or directory with the username &amp;quot;user&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot;
chown user /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;chown&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-R&lt;/code&gt; - Change the owner of a file or directory with the specified recursive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Change the owner of a file or directory with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Change the owner of a file or directory with the specified force.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Change the owner of a file or directory with the specified symbolic links.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Change the owner of a file or directory with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the owner of a file or directory with the username &amp;quot;user&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and recursive
chown -R user /home/user/file

# Change the owner of a file or directory with the username &amp;quot;user&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and verbose
chown -c user /home/user/file

# Change the owner of a file or directory with the username &amp;quot;user&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and force
chown -f user /home/user/file

# Change the owner of a file or directory with the username &amp;quot;user&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and symbolic links
chown -h user /home/user/file

# Change the owner of a file or directory with the username &amp;quot;user&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and verbose
chown -v user /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;chgrp&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;chgrp&lt;/code&gt; command is used to change the group of a file or directory. It takes a group name and a file or directory as arguments. The output of the &lt;code&gt;chgrp&lt;/code&gt; command is the file or directory that was changed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the group of a file or directory with the group name &amp;quot;group&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot;
chgrp group /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;chgrp&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-R&lt;/code&gt; - Change the group of a file or directory with the specified recursive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Change the group of a file or directory with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Change the group of a file or directory with the specified force.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Change the group of a file or directory with the specified symbolic links.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Change the group of a file or directory with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the group of a file or directory with the group name &amp;quot;group&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and recursive
chgrp -R group /home/user/file

# Change the group of a file or directory with the group name &amp;quot;group&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and verbose
chgrp -c group /home/user/file

# Change the group of a file or directory with the group name &amp;quot;group&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and force
chgrp -f group /home/user/file

# Change the group of a file or directory with the group name &amp;quot;group&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and symbolic links
chgrp -h group /home/user/file

# Change the group of a file or directory with the group name &amp;quot;group&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and verbose
chgrp -v group /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;chmod&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;chmod&lt;/code&gt; command is used to change the permissions of a file or directory. It takes a permission and a file or directory as arguments. The output of the &lt;code&gt;chmod&lt;/code&gt; command is the file or directory that was changed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the permissions of a file or directory with the permission &amp;quot;777&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot;
chmod 777 /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;Notice type=&quot;note&quot;&gt;
  The `chmod` command can also be used to change the permissions of a file or
  directory using the symbolic notation. 777 is the same as `rwxrwxrwx`. The
  first character is for the owner, the second character is for the group, and
  the third character is for everyone else. 7 is the same as `rwx`. 6 is the
  same as `rw-`. 5 is the same as `r-x`. 4 is the same as `r--`. 3 is the same
  as `-wx`. 2 is the same as `-w-`. 1 is the same as `--x`. 0 is the same as
  `---`.
&lt;/Notice&gt;&lt;h4&gt;&lt;code&gt;chmod&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-R&lt;/code&gt; - Change the permissions of a file or directory with the specified recursive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Change the permissions of a file or directory with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Change the permissions of a file or directory with the specified force.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Change the permissions of a file or directory with the specified symbolic links.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Change the permissions of a file or directory with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the permissions of a file or directory with the permission &amp;quot;777&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and recursive
chmod -R 777 /home/user/file

# Change the permissions of a file or directory with the permission &amp;quot;777&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and verbose
chmod -c 777 /home/user/file

# Change the permissions of a file or directory with the permission &amp;quot;777&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and force
chmod -f 777 /home/user/file

# Change the permissions of a file or directory with the permission &amp;quot;777&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and symbolic links
chmod -h 777 /home/user/file

# Change the permissions of a file or directory with the permission &amp;quot;777&amp;quot; and file or directory &amp;quot;/home/user/file&amp;quot; and verbose
chmod -v 777 /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;newgrp&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;newgrp&lt;/code&gt; command is used to change the group of the current user. It takes a group name as an argument. The output of the &lt;code&gt;newgrp&lt;/code&gt; command is the group that was changed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the group of the current user with the group name &amp;quot;group&amp;quot;
newgrp group
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;newgrp&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt; - Change the group of the current user with the specified login shell.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Change the group of the current user with the specified login shell.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Change the group of the current user with the specified login shell.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the group of the current user with the group name &amp;quot;group&amp;quot; and login shell
newgrp - group

# Change the group of the current user with the group name &amp;quot;group&amp;quot; and login shell
newgrp -l group

# Change the group of the current user with the group name &amp;quot;group&amp;quot; and login shell
newgrp -s group
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;setfacl&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;setfacl&lt;/code&gt; command is used to set the access control list of a file or directory. It takes a file or directory as an argument. The output of the &lt;code&gt;setfacl&lt;/code&gt; command is the file or directory that was changed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot;
setfacl /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;setfacl&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Set the access control list of a file or directory with the specified modify.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-x&lt;/code&gt; - Set the access control list of a file or directory with the specified remove.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Set the access control list of a file or directory with the specified remove all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Set the access control list of a file or directory with the specified remove default.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-R&lt;/code&gt; - Set the access control list of a file or directory with the specified recursive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Set the access control list of a file or directory with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Set the access control list of a file or directory with the specified force.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Set the access control list of a file or directory with the specified symbolic links.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Set the access control list of a file or directory with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and modify
setfacl -m /home/user/file

# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and remove
setfacl -x /home/user/file

# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and remove all
setfacl -b /home/user/file

# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and remove default
setfacl -k /home/user/file

# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and recursive
setfacl -R /home/user/file

# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and verbose
setfacl -c /home/user/file

# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and force
setfacl -f /home/user/file

# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and symbolic links
setfacl -h /home/user/file

# Set the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and verbose
setfacl -v /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;umask&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;umask&lt;/code&gt; command is used to set the default permissions of a file or directory. It takes a permission as an argument. The output of the &lt;code&gt;umask&lt;/code&gt; command is the permission that was changed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Set the default permissions of a file or directory with the permission &amp;quot;777&amp;quot;
umask 777
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;umask&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-S&lt;/code&gt; - Set the default permissions of a file or directory with the specified symbolic notation.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Set the default permissions of a file or directory with the permission &amp;quot;777&amp;quot; and symbolic notation
umask -S 777
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;getfacl&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;getfacl&lt;/code&gt; command is used to get the access control list of a file or directory. It takes a file or directory as an argument. The output of the &lt;code&gt;getfacl&lt;/code&gt; command is the access control list of the file or directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot;
getfacl /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;getfacl&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-R&lt;/code&gt; - Get the access control list of a file or directory with the specified recursive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Get the access control list of a file or directory with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Get the access control list of a file or directory with the specified force.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Get the access control list of a file or directory with the specified symbolic links.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Get the access control list of a file or directory with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and recursive
getfacl -R /home/user/file

# Get the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and verbose
getfacl -c /home/user/file

# Get the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and force
getfacl -f /home/user/file

# Get the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and symbolic links
getfacl -h /home/user/file

# Get the access control list of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and verbose
getfacl -v /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;chattr&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;chattr&lt;/code&gt; command is used to change the attributes of a file or directory. It takes a file or directory as an argument. The output of the &lt;code&gt;chattr&lt;/code&gt; command is the file or directory that was changed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot;
chattr /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;chattr&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Change the attributes of a file or directory with the specified immutable.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Change the attributes of a file or directory with the specified append only.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-A&lt;/code&gt; - Change the attributes of a file or directory with the specified no append.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Change the attributes of a file or directory with the specified no dump.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-D&lt;/code&gt; - Change the attributes of a file or directory with the specified dump.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; - Change the attributes of a file or directory with the specified extent.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-E&lt;/code&gt; - Change the attributes of a file or directory with the specified no extent.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Change the attributes of a file or directory with the specified no follow.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-H&lt;/code&gt; - Change the attributes of a file or directory with the specified follow.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-j&lt;/code&gt; - Change the attributes of a file or directory with the specified data journaling.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-J&lt;/code&gt; - Change the attributes of a file or directory with the specified no data journaling.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Change the attributes of a file or directory with the specified secure deletion.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-S&lt;/code&gt; - Change the attributes of a file or directory with the specified no secure deletion.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Change the attributes of a file or directory with the specified notail.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-T&lt;/code&gt; - Change the attributes of a file or directory with the specified tail.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Change the attributes of a file or directory with the specified undelete.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-U&lt;/code&gt; - Change the attributes of a file or directory with the specified no undelete.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Change the attributes of a file or directory with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and immutable
chattr -i /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and append only
chattr -a /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and no append
chattr -A /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and no dump
chattr -d /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and dump
chattr -D /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and extent
chattr -e /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and no extent
chattr -E /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and no follow
chattr -h /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and follow
chattr -H /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and data journaling
chattr -j /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and no data journaling
chattr -J /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and secure deletion
chattr -s /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and no secure deletion
chattr -S /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and notail
chattr -t /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and tail
chattr -T /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and undelete
chattr -u /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and no undelete
chattr -U /home/user/file

# Change the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and verbose
chattr -v /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;lsattr&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;lsattr&lt;/code&gt; command is used to list the attributes of a file or directory. It takes a file or directory as an argument. The output of the &lt;code&gt;lsattr&lt;/code&gt; command is the attributes of the file or directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# List the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot;
lsattr /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;lsattr&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-R&lt;/code&gt; - List the attributes of a file or directory with the specified recursive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - List the attributes of a file or directory with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - List the attributes of a file or directory with the specified directory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - List the attributes of a file or directory with the specified symbolic links.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - List the attributes of a file or directory with the specified long format.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - List the attributes of a file or directory with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# List the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and recursive
lsattr -R /home/user/file

# List the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and all
lsattr -a /home/user/file

# List the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and directory
lsattr -d /home/user/file

# List the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and symbolic links
lsattr -h /home/user/file

# List the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and long format
lsattr -l /home/user/file

# List the attributes of a file or directory with the file or directory &amp;quot;/home/user/file&amp;quot; and verbose
lsattr -v /home/user/file
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h2&gt;Check System Information&lt;/h2&gt;
&lt;p&gt;You must be acquainted with these commands if you want to be a system and Linux administrator. These, such as load, CPU model, hardware model, hardware type, etc., will assist you in identifying the sort of server you are using.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;uptime&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;uptime&lt;/code&gt; command is used to display the system uptime. It takes no arguments. The output of the &lt;code&gt;uptime&lt;/code&gt; command is the system uptime.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the system uptime
uptime
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;uptime&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Display the system uptime with the specified pretty format.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Display the system uptime with the specified since.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Display the system uptime with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the system uptime with the specified pretty format
uptime -p

# Display the system uptime with the specified since
uptime -s

# Display the system uptime with the specified version
uptime -V
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;uname&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;uname&lt;/code&gt; command is used to display the system information. It takes no arguments. The output of the &lt;code&gt;uname&lt;/code&gt; command is the system information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the system information
uname
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;uname&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Display the system information with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Display the system information with the specified machine.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Display the system information with the specified nodename.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Display the system information with the specified kernel release.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Display the system information with the specified kernel name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Display the system information with the specified kernel version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the system information with the specified all
uname -a

# Display the system information with the specified machine
uname -m

# Display the system information with the specified nodename
uname -n

# Display the system information with the specified kernel release
uname -r

# Display the system information with the specified kernel name
uname -s

# Display the system information with the specified kernel version
uname -v
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;lscpu&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;lscpu&lt;/code&gt; command is used to display the CPU information. It takes no arguments. The output of the &lt;code&gt;lscpu&lt;/code&gt; command is the CPU information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the CPU information
lscpu
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;lscpu&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Display the CPU information with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; - Display the CPU information with the specified extended.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Display the CPU information with the specified human-readable.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Display the CPU information with the specified size in bytes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Display the CPU information with the specified physical.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-x&lt;/code&gt; - Display the CPU information with the specified XML.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the CPU information with the specified all
lscpu -a

# Display the CPU information with the specified extended
lscpu -e

# Display the CPU information with the specified human-readable
lscpu -h

# Display the CPU information with the specified size in bytes
lscpu -i

# Display the CPU information with the specified physical
lscpu -p

# Display the CPU information with the specified XML
lscpu -x
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;lspci&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;lspci&lt;/code&gt; command is used to display the PCI information. It takes no arguments. The output of the &lt;code&gt;lspci&lt;/code&gt; command is the PCI information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the PCI information
lspci
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;lspci&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Display the PCI information with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Display the PCI information with the specified brief.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Display the PCI information with the specified device.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-D&lt;/code&gt; - Display the PCI information with the specified dump.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Display the PCI information with the specified kernel.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Display the PCI information with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Display the PCI information with the specified slot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Display the PCI information with the specified tree.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Display the PCI information with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the PCI information with the specified all
lspci -a

# Display the PCI information with the specified brief
lspci -b

# Display the PCI information with the specified device
lspci -d

# Display the PCI information with the specified dump
lspci -D

# Display the PCI information with the specified kernel
lspci -k

# Display the PCI information with the specified numeric
lspci -n

# Display the PCI information with the specified slot
lspci -s

# Display the PCI information with the specified tree
lspci -t

# Display the PCI information with the specified verbose
lspci -v
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;lsusb&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;lsusb&lt;/code&gt; command is used to display the USB information. It takes no arguments. The output of the &lt;code&gt;lsusb&lt;/code&gt; command is the USB information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the USB information
lsusb
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;lsusb&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Display the USB information with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Display the USB information with the specified brief.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Display the USB information with the specified device.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-D&lt;/code&gt; - Display the USB information with the specified dump.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Display the USB information with the specified kernel.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Display the USB information with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Display the USB information with the specified slot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Display the USB information with the specified tree.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Display the USB information with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the USB information with the specified all
lsusb -a

# Display the USB information with the specified brief
lsusb -b

# Display the USB information with the specified device
lsusb -d

# Display the USB information with the specified dump
lsusb -D

# Display the USB information with the specified kernel
lsusb -k

# Display the USB information with the specified numeric
lsusb -n

# Display the USB information with the specified slot
lsusb -s

# Display the USB information with the specified tree
lsusb -t

# Display the USB information with the specified verbose
lsusb -v
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;free&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;free&lt;/code&gt; command is used to display the memory information. It takes no arguments. The output of the &lt;code&gt;free&lt;/code&gt; command is the memory information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the memory information
free
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;free&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Display the memory information with the specified bytes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Display the memory information with the specified kilobytes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Display the memory information with the specified megabytes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-g&lt;/code&gt; - Display the memory information with the specified gigabytes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Display the memory information with the specified human-readable.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Display the memory information with the specified total.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Display the memory information with the specified seconds.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Display the memory information with the specified continuous.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o&lt;/code&gt; - Display the memory information with the specified omit header.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Display the memory information with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the memory information with the specified bytes
free -b

# Display the memory information with the specified kilobytes
free -k

# Display the memory information with the specified megabytes
free -m

# Display the memory information with the specified gigabytes
free -g

# Display the memory information with the specified human-readable
free -h

# Display the memory information with the specified total
free -t

# Display the memory information with the specified seconds
free -s

# Display the memory information with the specified continuous
free -c

# Display the memory information with the specified omit header
free -o

# Display the memory information with the specified version
free -V
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h2&gt;Configure and Troubleshoot Network&lt;/h2&gt;
&lt;p&gt;Network engineers fresh to the Linux environment can benefit from reading this section. I made an effort to include the most used network troubleshooting commands. Tcpdump, iperf, netperf, and several more networking tools are also available for debugging network-related problems, but because of their complexity, they are not included in this list.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;ifconfig&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ifconfig&lt;/code&gt; command is used to configure and display the network interface information. It takes no arguments. The output of the &lt;code&gt;ifconfig&lt;/code&gt; command is the network interface information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the network interface information
ifconfig
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;ifconfig&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Display the network interface information with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Display the network interface information with the specified summary.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Display the network interface information with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Display the network interface information with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the network interface information with the specified all
ifconfig -a

# Display the network interface information with the specified summary
ifconfig -s

# Display the network interface information with the specified verbose
ifconfig -v

# Display the network interface information with the specified version
ifconfig -V
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;ip&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ip&lt;/code&gt; command is used to configure and display the network interface information. It takes no arguments. The output of the &lt;code&gt;ip&lt;/code&gt; command is the network interface information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the network interface information
ip
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;ip&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Display the network interface information with the specified statistics.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Display the network interface information with the specified details.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Display the network interface information with the specified help.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Display the network interface information with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Display the network interface information with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the network interface information with the specified statistics
ip -s

# Display the network interface information with the specified details
ip -d

# Display the network interface information with the specified help
ip -h

# Display the network interface information with the specified verbose
ip -v

# Display the network interface information with the specified version
ip -V
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;netstat&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;netstat&lt;/code&gt; command is used to display the network information. It takes no arguments. The output of the &lt;code&gt;netstat&lt;/code&gt; command is the network information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the network information
netstat
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;netstat&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Display the network information with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Display the network information with the specified continuous.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; - Display the network information with the specified extended.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-g&lt;/code&gt; - Display the network information with the specified multicast.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Display the network information with the specified interfaces.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Display the network information with the specified listening.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Display the network information with the specified memory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Display the network information with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Display the network information with the specified protocol.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Display the network information with the specified routing.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the network information with the specified all
netstat -a

# Display the network information with the specified continuous
netstat -c

# Display the network information with the specified extended
netstat -e

# Display the network information with the specified multicast
netstat -g

# Display the network information with the specified interfaces
netstat -i

# Display the network information with the specified listening
netstat -l

# Display the network information with the specified memory
netstat -m

# Display the network information with the specified numeric
netstat -n

# Display the network information with the specified protocol
netstat -p

# Display the network information with the specified routing
netstat -r
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;route&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;route&lt;/code&gt; command is used to display the routing information. It takes no arguments. The output of the &lt;code&gt;route&lt;/code&gt; command is the routing information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the routing information
route
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;route&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Display the routing information with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Display the routing information with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Display the routing information with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the routing information with the specified numeric
route -n

# Display the routing information with the specified verbose
route -v

# Display the routing information with the specified version
route -V
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;ethtool&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ethtool&lt;/code&gt; command is used to display the network interface information. It takes no arguments. The output of the &lt;code&gt;ethtool&lt;/code&gt; command is the network interface information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the network interface information
ethtool
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;ethtool&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Display the network interface information with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Display the network interface information with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Display the network interface information with the specified kernel.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-S&lt;/code&gt; - Display the network interface information with the specified statistics.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Display the network interface information with the specified command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Display the network interface information with the specified help.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Display the network interface information with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the network interface information with the specified all
ethtool -a

# Display the network interface information with the specified interface
ethtool -i

# Display the network interface information with the specified kernel
ethtool -k

# Display the network interface information with the specified statistics
ethtool -S

# Display the network interface information with the specified command
ethtool -c

# Display the network interface information with the specified help
ethtool -h

# Display the network interface information with the specified version
ethtool -V
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;tcpdump&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;tcpdump&lt;/code&gt; command is used to capture and display the network packets. It takes no arguments. The output of the &lt;code&gt;tcpdump&lt;/code&gt; command is the network packets.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Capture and display the network packets
tcpdump
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;tcpdump&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Capture and display the network packets with the specified count.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Capture and display the network packets with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Capture and display the network packets with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Capture and display the network packets with the specified read.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Capture and display the network packets with the specified snapshot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-w&lt;/code&gt; - Capture and display the network packets with the specified write.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-A&lt;/code&gt; - Capture and display the network packets with the specified ASCII.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-C&lt;/code&gt; - Capture and display the network packets with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-D&lt;/code&gt; - Capture and display the network packets with the specified devices.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-F&lt;/code&gt; - Capture and display the network packets with the specified output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-G&lt;/code&gt; - Capture and display the network packets with the specified rotate.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-H&lt;/code&gt; - Capture and display the network packets with the specified hex.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-L&lt;/code&gt; - Capture and display the network packets with the specified follow.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-N&lt;/code&gt; - Capture and display the network packets with the specified no.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-S&lt;/code&gt; - Capture and display the network packets with the specified size.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-T&lt;/code&gt; - Capture and display the network packets with the specified timestamp.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-Z&lt;/code&gt; - Capture and display the network packets with the specified user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Capture and display the network packets with the specified decode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Capture and display the network packets with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Capture and display the network packets with the specified count
tcpdump -c

# Capture and display the network packets with the specified interface
tcpdump -i

# Capture and display the network packets with the specified numeric
tcpdump -n

# Capture and display the network packets with the specified read
tcpdump -r

# Capture and display the network packets with the specified snapshot
tcpdump -s

# Capture and display the network packets with the specified write
tcpdump -w

# Capture and display the network packets with the specified ASCII
tcpdump -A

# Capture and display the network packets with the specified file
tcpdump -C

# Capture and display the network packets with the specified devices
tcpdump -D

# Capture and display the network packets with the specified output
tcpdump -F

# Capture and display the network packets with the specified rotate
tcpdump -G

# Capture and display the network packets with the specified hex
tcpdump -H

# Capture and display the network packets with the specified follow
tcpdump -L

# Capture and display the network packets with the specified no
tcpdump -N

# Capture and display the network packets with the specified size
tcpdump -S

# Capture and display the network packets with the specified timestamp
tcpdump -T

# Capture and display the network packets with the specified user
tcpdump -Z

# Capture and display the network packets with the specified decode
tcpdump -d

# Capture and display the network packets with the specified version
tcpdump -V
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;ping&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ping&lt;/code&gt; command is used to send the ICMP echo request packets to the specified host. It takes no arguments. The output of the &lt;code&gt;ping&lt;/code&gt; command is the ICMP echo reply packets.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Send the ICMP echo request packets to the specified host
ping &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;ping&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Send the ICMP echo request packets to the specified host with the specified count.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Send the ICMP echo request packets to the specified host with the specified interval.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-I&lt;/code&gt; - Send the ICMP echo request packets to the specified host with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Send the ICMP echo request packets to the specified host with the specified size.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Send the ICMP echo request packets to the specified host with the specified ttl.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Send the ICMP echo request packets to the specified host with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Send the ICMP echo request packets to the specified host with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Send the ICMP echo request packets to the specified host with the specified count
ping -c &amp;lt;host&amp;gt;

# Send the ICMP echo request packets to the specified host with the specified interval
ping -i &amp;lt;host&amp;gt;

# Send the ICMP echo request packets to the specified host with the specified interface
ping -I &amp;lt;host&amp;gt;

# Send the ICMP echo request packets to the specified host with the specified size
ping -s &amp;lt;host&amp;gt;

# Send the ICMP echo request packets to the specified host with the specified ttl
ping -t &amp;lt;host&amp;gt;

# Send the ICMP echo request packets to the specified host with the specified verbose
ping -v &amp;lt;host&amp;gt;

# Send the ICMP echo request packets to the specified host with the specified version
ping -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;traceroute&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;traceroute&lt;/code&gt; command is used to trace the route to the specified host. It takes no arguments. The output of the &lt;code&gt;traceroute&lt;/code&gt; command is the route to the specified host.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Trace the route to the specified host
traceroute &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;traceroute&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Trace the route to the specified host with the specified debug.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Trace the route to the specified host with the specified first.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-g&lt;/code&gt; - Trace the route to the specified host with the specified gateway.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-I&lt;/code&gt; - Trace the route to the specified host with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Trace the route to the specified host with the specified max.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Trace the route to the specified host with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Trace the route to the specified host with the specified port.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Trace the route to the specified host with the specified query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Trace the route to the specified host with the specified source.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Trace the route to the specified host with the specified ttl.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Trace the route to the specified host with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Trace the route to the specified host with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Trace the route to the specified host with the specified debug
traceroute -d &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified first
traceroute -f &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified gateway
traceroute -g &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified interface
traceroute -I &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified max
traceroute -m &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified numeric
traceroute -n &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified port
traceroute -p &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified query
traceroute -q &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified source
traceroute -s &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified ttl
traceroute -t &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified verbose
traceroute -v &amp;lt;host&amp;gt;

# Trace the route to the specified host with the specified version
traceroute -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;dig&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;dig&lt;/code&gt; command is used to query the DNS name servers. It takes no arguments. The output of the &lt;code&gt;dig&lt;/code&gt; command is the DNS name servers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers
dig &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;dig&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Query the DNS name servers with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Query the DNS name servers with the specified bind.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Query the DNS name servers with the specified class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Query the DNS name servers with the specified debug.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Query the DNS name servers with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Query the DNS name servers with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Query the DNS name servers with the specified key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Query the DNS name servers with the specified max.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Query the DNS name servers with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Query the DNS name servers with the specified port.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Query the DNS name servers with the specified query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Query the DNS name servers with the specified recurse.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Query the DNS name servers with the specified server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Query the DNS name servers with the specified type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Query the DNS name servers with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Query the DNS name servers with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers with the specified all
dig -a &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified bind
dig -b &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified class
dig -c &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified debug
dig -d &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified file
dig -f &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified interface
dig -i &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified key
dig -k &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified max
dig -m &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified numeric
dig -n &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified port
dig -p &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified query
dig -q &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified recurse
dig -r &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified server
dig -s &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified type
dig -t &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified verbose
dig -v &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified version
dig -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;nslookup&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;nslookup&lt;/code&gt; command is used to query the DNS name servers. It takes no arguments. The output of the &lt;code&gt;nslookup&lt;/code&gt; command is the DNS name servers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers
nslookup &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;nslookup&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Query the DNS name servers with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Query the DNS name servers with the specified bind.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Query the DNS name servers with the specified class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Query the DNS name servers with the specified debug.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Query the DNS name servers with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Query the DNS name servers with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Query the DNS name servers with the specified key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Query the DNS name servers with the specified max.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Query the DNS name servers with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Query the DNS name servers with the specified port.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Query the DNS name servers with the specified query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Query the DNS name servers with the specified recurse.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Query the DNS name servers with the specified server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Query the DNS name servers with the specified type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Query the DNS name servers with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Query the DNS name servers with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers with the specified all
nslookup -a &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified bind
nslookup -b &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified class
nslookup -c &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified debug
nslookup -d &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified file
nslookup -f &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified interface
nslookup -i &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified key
nslookup -k &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified max
nslookup -m &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified numeric
nslookup -n &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified port
nslookup -p &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified query
nslookup -q &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified recurse
nslookup -r &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified server
nslookup -s &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified type
nslookup -t &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified verbose
nslookup -v &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified version
nslookup -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;host&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;host&lt;/code&gt; command is used to query the DNS name servers. It takes no arguments. The output of the &lt;code&gt;host&lt;/code&gt; command is the DNS name servers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers
host &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;host&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Query the DNS name servers with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Query the DNS name servers with the specified bind.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Query the DNS name servers with the specified class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Query the DNS name servers with the specified debug.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Query the DNS name servers with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Query the DNS name servers with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Query the DNS name servers with the specified key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Query the DNS name servers with the specified max.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Query the DNS name servers with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Query the DNS name servers with the specified port.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Query the DNS name servers with the specified query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Query the DNS name servers with the specified recurse.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Query the DNS name servers with the specified server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Query the DNS name servers with the specified type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Query the DNS name servers with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Query the DNS name servers with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers with the specified all
host -a &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified bind
host -b &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified class
host -c &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified debug
host -d &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified file
host -f &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified interface
host -i &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified key
host -k &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified max
host -m &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified numeric
host -n &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified port
host -p &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified query
host -q &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified recurse
host -r &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified server
host -s &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified type
host -t &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified verbose
host -v &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified version
host -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;drill&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;drill&lt;/code&gt; command is used to query the DNS name servers. It takes no arguments. The output of the &lt;code&gt;drill&lt;/code&gt; command is the DNS name servers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers
drill &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;drill&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Query the DNS name servers with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Query the DNS name servers with the specified bind.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Query the DNS name servers with the specified class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Query the DNS name servers with the specified debug.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Query the DNS name servers with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Query the DNS name servers with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Query the DNS name servers with the specified key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Query the DNS name servers with the specified max.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Query the DNS name servers with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Query the DNS name servers with the specified port.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Query the DNS name servers with the specified query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Query the DNS name servers with the specified recurse.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Query the DNS name servers with the specified server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Query the DNS name servers with the specified type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Query the DNS name servers with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Query the DNS name servers with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers with the specified all
drill -a &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified bind
drill -b &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified class
drill -c &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified debug
drill -d &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified file
drill -f &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified interface
drill -i &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified key
drill -k &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified max
drill -m &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified numeric
drill -n &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified port
drill -p &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified query
drill -q &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified recurse
drill -r &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified server
drill -s &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified type
drill -t &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified verbose
drill -v &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified version
drill -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;ss&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ss&lt;/code&gt; command is used to query the DNS name servers. It takes no arguments. The output of the &lt;code&gt;ss&lt;/code&gt; command is the DNS name servers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers
ss &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;ss&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Query the DNS name servers with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Query the DNS name servers with the specified bind.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Query the DNS name servers with the specified class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Query the DNS name servers with the specified debug.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Query the DNS name servers with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Query the DNS name servers with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Query the DNS name servers with the specified key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Query the DNS name servers with the specified max.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Query the DNS name servers with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Query the DNS name servers with the specified port.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Query the DNS name servers with the specified query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Query the DNS name servers with the specified recurse.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Query the DNS name servers with the specified server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Query the DNS name servers with the specified type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Query the DNS name servers with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Query the DNS name servers with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers with the specified all
ss -a &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified bind
ss -b &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified class
ss -c &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified debug
ss -d &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified file
ss -f &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified interface
ss -i &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified key
ss -k &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified max
ss -m &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified numeric
ss -n &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified port
ss -p &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified query
ss -q &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified recurse
ss -r &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified server
ss -s &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified type
ss -t &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified verbose
ss -v &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified version
ss -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;wget&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;wget&lt;/code&gt; command is used to query the DNS name servers. It takes no arguments. The output of the &lt;code&gt;wget&lt;/code&gt; command is the DNS name servers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers
wget &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;wget&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Query the DNS name servers with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Query the DNS name servers with the specified bind.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Query the DNS name servers with the specified class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Query the DNS name servers with the specified debug.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Query the DNS name servers with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Query the DNS name servers with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Query the DNS name servers with the specified key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Query the DNS name servers with the specified max.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Query the DNS name servers with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Query the DNS name servers with the specified port.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Query the DNS name servers with the specified query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Query the DNS name servers with the specified recurse.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Query the DNS name servers with the specified server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Query the DNS name servers with the specified type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Query the DNS name servers with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Query the DNS name servers with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers with the specified all
wget -a &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified bind
wget -b &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified class
wget -c &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified debug
wget -d &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified file
wget -f &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified interface
wget -i &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified key
wget -k &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified max
wget -m &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified numeric
wget -n &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified port
wget -p &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified query
wget -q &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified recurse
wget -r &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified server
wget -s &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified type
wget -t &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified verbose
wget -v &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified version
wget -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;curl&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;curl&lt;/code&gt; command is used to query the DNS name servers. It takes no arguments. The output of the &lt;code&gt;curl&lt;/code&gt; command is the DNS name servers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers
curl &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;curl&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Query the DNS name servers with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Query the DNS name servers with the specified bind.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Query the DNS name servers with the specified class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Query the DNS name servers with the specified debug.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Query the DNS name servers with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Query the DNS name servers with the specified interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Query the DNS name servers with the specified key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Query the DNS name servers with the specified max.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Query the DNS name servers with the specified numeric.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Query the DNS name servers with the specified port.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Query the DNS name servers with the specified query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Query the DNS name servers with the specified recurse.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Query the DNS name servers with the specified server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Query the DNS name servers with the specified type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Query the DNS name servers with the specified verbose.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Query the DNS name servers with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers with the specified all
curl -a &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified bind
curl -b &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified class
curl -c &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified debug
curl -d &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified file
curl -f &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified interface
curl -i &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified key
curl -k &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified max
curl -m &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified numeric
curl -n &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified port
curl -p &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified query
curl -q &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified recurse
curl -r &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified server
curl -s &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified type
curl -t &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified verbose
curl -v &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified version
curl -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;nmap&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;nmap&lt;/code&gt; command is used to query the DNS name servers. It takes no arguments. The output of the &lt;code&gt;nmap&lt;/code&gt; command is the DNS name servers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers
nmap &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;nmap&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-A&lt;/code&gt; - Query the DNS name servers with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-V&lt;/code&gt; - Query the DNS name servers with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Query the DNS name servers with the specified all
nmap -A &amp;lt;host&amp;gt;

# Query the DNS name servers with the specified version
nmap -V &amp;lt;host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h2&gt;Manage System Processes&lt;/h2&gt;
&lt;p&gt;You may control Linux processes and troubleshoot any server resource-related issues with the use of these Linux commands. These commands let you keep an eye on your server&amp;#39;s RAM, CPU, disk IO, and other resources.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;ps&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ps&lt;/code&gt; command is used to list the processes running on the system. It takes no arguments. The output of the &lt;code&gt;ps&lt;/code&gt; command is the processes running on the system.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# List the processes running on the system
ps
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;ps&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - List the processes running on the system with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - List the processes running on the system with the specified full.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - List the processes running on the system with the specified long.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - List the processes running on the system with the specified user.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# List the processes running on the system with the specified all
ps -a

# List the processes running on the system with the specified full
ps -f

# List the processes running on the system with the specified long
ps -l

# List the processes running on the system with the specified user
ps -u
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;top&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;top&lt;/code&gt; command is used to display the processes running on the system. It takes no arguments. The output of the &lt;code&gt;top&lt;/code&gt; command is the processes running on the system.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the processes running on the system
top
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;top&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Display the processes running on the system with the specified batch.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Display the processes running on the system with the specified command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Display the processes running on the system with the specified delay.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Display the processes running on the system with the specified help.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Display the processes running on the system with the specified idle.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Display the processes running on the system with the specified iterations.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Display the processes running on the system with the specified pid.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Display the processes running on the system with the specified sort.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Display the processes running on the system with the specified user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Display the processes running on the system with the specified version.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Display the processes running on the system with the specified batch
top -b

# Display the processes running on the system with the specified command
top -c

# Display the processes running on the system with the specified delay
top -d

# Display the processes running on the system with the specified help
top -h

# Display the processes running on the system with the specified idle
top -i

# Display the processes running on the system with the specified iterations
top -n

# Display the processes running on the system with the specified pid
top -p

# Display the processes running on the system with the specified sort
top -s

# Display the processes running on the system with the specified user
top -u

# Display the processes running on the system with the specified version
top -v
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;kill&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;kill&lt;/code&gt; command is used to kill a process. It takes one argument. The output of the &lt;code&gt;kill&lt;/code&gt; command is the killed process.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Kill a process
kill &amp;lt;pid&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;kill&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Kill a process with the specified list.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Kill a process with the specified list
kill -l &amp;lt;pid&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;killall&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;killall&lt;/code&gt; command is used to kill a process. It takes one argument. The output of the &lt;code&gt;killall&lt;/code&gt; command is the killed process.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Kill a process
killall &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;killall&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Kill a process with the specified list.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Kill a process with the specified list
killall -l &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;pkill&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;pkill&lt;/code&gt; command is used to kill a process. It takes one argument. The output of the &lt;code&gt;pkill&lt;/code&gt; command is the killed process.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Kill a process
pkill &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;pkill&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Kill a process with the specified list.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Kill a process with the specified list
pkill -l &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;pgrep&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;pgrep&lt;/code&gt; command is used to kill a process. It takes one argument. The output of the &lt;code&gt;pgrep&lt;/code&gt; command is the killed process.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Kill a process
pgrep &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;pgrep&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Kill a process with the specified list.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Kill a process with the specified list
pgrep -l &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;nice&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;nice&lt;/code&gt; command is used to run a process with a nice value. It takes one argument. The output of the &lt;code&gt;nice&lt;/code&gt; command is the process with a nice value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process with a nice value
nice &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;nice&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Run a process with a nice value with the specified nice.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Run a process with a nice value with the specified pid.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Run a process with a nice value with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process with a nice value with the specified nice
nice -n &amp;lt;process&amp;gt;

# Run a process with a nice value with the specified pid
nice -p &amp;lt;process&amp;gt;

# Run a process with a nice value with the specified verbose
nice -v &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;renice&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;renice&lt;/code&gt; command is used to run a process with a nice value. It takes one argument. The output of the &lt;code&gt;renice&lt;/code&gt; command is the process with a nice value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process with a nice value
renice &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;renice&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Run a process with a nice value with the specified nice.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Run a process with a nice value with the specified pid.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Run a process with a nice value with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process with a nice value with the specified nice
renice -n &amp;lt;process&amp;gt;

# Run a process with a nice value with the specified pid
renice -p &amp;lt;process&amp;gt;

# Run a process with a nice value with the specified verbose
renice -v &amp;lt;process&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;at&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;at&lt;/code&gt; command is used to run a process at a specified time. It takes one argument. The output of the &lt;code&gt;at&lt;/code&gt; command is the process at a specified time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time
at &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;at&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Run a process at a specified time with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Run a process at a specified time with the specified queue.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Run a process at a specified time with the specified remove.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Run a process at a specified time with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time with the specified file
at -f &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified queue
at -q &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified remove
at -r &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified verbose
at -v &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;atq&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;atq&lt;/code&gt; command is used to run a process at a specified time. It takes one argument. The output of the &lt;code&gt;atq&lt;/code&gt; command is the process at a specified time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time
atq &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;atq&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Run a process at a specified time with the specified clear.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Run a process at a specified time with the specified queue.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Run a process at a specified time with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time with the specified clear
atq -c &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified queue
atq -q &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified verbose
atq -v &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;atrm&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;atrm&lt;/code&gt; command is used to run a process at a specified time. It takes one argument. The output of the &lt;code&gt;atrm&lt;/code&gt; command is the process at a specified time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time
atrm &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;atrm&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Run a process at a specified time with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time with the specified verbose
atrm -v &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;batch&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;batch&lt;/code&gt; command is used to run a process at a specified time. It takes one argument. The output of the &lt;code&gt;batch&lt;/code&gt; command is the process at a specified time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time
batch &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;batch&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Run a process at a specified time with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Run a process at a specified time with the specified queue.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Run a process at a specified time with the specified remove.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Run a process at a specified time with the specified verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time with the specified file
batch -f &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified queue
batch -q &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified remove
batch -r &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified verbose
batch -v &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;crontab&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;crontab&lt;/code&gt; command is used to run a process at a specified time. It takes one argument. The output of the &lt;code&gt;crontab&lt;/code&gt; command is the process at a specified time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time
crontab &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;crontab&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; - Run a process at a specified time with the specified edit.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Run a process at a specified time with the specified list.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Run a process at a specified time with the specified remove.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time with the specified edit
crontab -e &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified list
crontab -l &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified remove
crontab -r &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;iostat&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;iostat&lt;/code&gt; command is used to run a process at a specified time. It takes one argument. The output of the &lt;code&gt;iostat&lt;/code&gt; command is the process at a specified time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time
iostat &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;iostat&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; - Run a process at a specified time with the specified count.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Run a process at a specified time with the specified device.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Run a process at a specified time with the specified help.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Run a process at a specified time with the specified kilobytes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Run a process at a specified time with the specified megabytes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Run a process at a specified time with the specified partition.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Run a process at a specified time with the specified quiet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Run a process at a specified time with the specified time.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-x&lt;/code&gt; - Run a process at a specified time with the specified extended.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-y&lt;/code&gt; - Run a process at a specified time with the specified summary.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time with the specified count
iostat -c &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified device
iostat -d &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified help
iostat -h &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified kilobytes
iostat -k &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified megabytes
iostat -m &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified partition
iostat -p &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified quiet
iostat -q &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified time
iostat -t &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified extended
iostat -x &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified summary
iostat -y &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;vmstat&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;vmstat&lt;/code&gt; command is used to run a process at a specified time. It takes one argument. The output of the &lt;code&gt;vmstat&lt;/code&gt; command is the process at a specified time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time
vmstat &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;vmstat&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Run a process at a specified time with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Run a process at a specified time with the specified disk.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Run a process at a specified time with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Run a process at a specified time with the specified help.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Run a process at a specified time with the specified interrupt.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time with the specified all
vmstat -a &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified disk
vmstat -d &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified file
vmstat -f &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified help
vmstat -h &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified interrupt
vmstat -i &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h3&gt;&lt;code&gt;sar&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;sar&lt;/code&gt; command is used to run a process at a specified time. It takes one argument. The output of the &lt;code&gt;sar&lt;/code&gt; command is the process at a specified time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time
sar &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;sar&lt;/code&gt; Flags&lt;/h4&gt;
&lt;details&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-A&lt;/code&gt; - Run a process at a specified time with the specified all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-B&lt;/code&gt; - Run a process at a specified time with the specified block.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Run a process at a specified time with the specified boot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Run a process at a specified time with the specified device.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; - Run a process at a specified time with the specified error.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Run a process at a specified time with the specified file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; - Run a process at a specified time with the specified help.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-H&lt;/code&gt; - Run a process at a specified time with the specified huge.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-I&lt;/code&gt; - Run a process at a specified time with the specified interrupt.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-j&lt;/code&gt; - Run a process at a specified time with the specified job.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-k&lt;/code&gt; - Run a process at a specified time with the specified kernel.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Run a process at a specified time with the specified lock.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Run a process at a specified time with the specified memory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Run a process at a specified time with the specified network.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o&lt;/code&gt; - Run a process at a specified time with the specified output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Run a process at a specified time with the specified partition.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Run a process at a specified time with the specified queue.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Run a process at a specified time with the specified remove.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-R&lt;/code&gt; - Run a process at a specified time with the specified reboot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-S&lt;/code&gt; - Run a process at a specified time with the specified swap.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Run a process at a specified time with the specified system.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Run a process at a specified time with the specified time.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt; - Run a process at a specified time with the specified user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Run a process at a specified time with the specified version.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-w&lt;/code&gt; - Run a process at a specified time with the specified wait.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-W&lt;/code&gt; - Run a process at a specified time with the specified watchdog.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-x&lt;/code&gt; - Run a process at a specified time with the specified extended.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-y&lt;/code&gt; - Run a process at a specified time with the specified summary.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Run a process at a specified time with the specified all
sar -A &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified block
sar -B &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified boot
sar -b &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified device
sar -d &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified error
sar -e &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified file
sar -f &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified help
sar -h &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified huge
sar -H &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified interrupt
sar -I &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified job
sar -j &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified kernel
sar -k &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified lock
sar -l &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified memory
sar -m &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified network
sar -n &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified output
sar -o &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified partition
sar -p &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified queue
sar -q &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified remove
sar -r &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified reboot
sar -R &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified swap
sar -S &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified system
sar -s &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified time
sar -t &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified user
sar -u &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified version
sar -v &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified wait
sar -w &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified watchdog
sar -W &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified extended
sar -x &amp;lt;time&amp;gt;

# Run a process at a specified time with the specified summary
sar -y &amp;lt;time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;You learnt about Linux CLI commands in this tutorial, along with the fundamental commands for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;File Management&lt;/li&gt;
&lt;li&gt;Finding files and directories&lt;/li&gt;
&lt;li&gt;Check User Information&lt;/li&gt;
&lt;li&gt;Managing Users and Groups&lt;/li&gt;
&lt;li&gt;Managing Permissions&lt;/li&gt;
&lt;li&gt;Check System Information&lt;/li&gt;
&lt;li&gt;Configure and Troubleshoot Network&lt;/li&gt;
&lt;li&gt;Manage System Processes&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://linuxcommand.org/tlcl.php&quot;&gt;The Linux Command Line by William Shotts (Free Book)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linuxjourney.com/&quot;&gt;Linux Journey - Learning Portal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://manpages.ubuntu.com/&quot;&gt;Ubuntu Manpages Online&lt;/a&gt; (Useful for checking specific command options)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/coreutils/manual/coreutils.html&quot;&gt;GNU Coreutils Manual&lt;/a&gt; (Covers many basic commands like &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Command-line_shell&quot;&gt;ArchWiki - Command-line shell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/&quot;&gt;Red Hat Enterprise Linux Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://debian-handbook.info/browse/stable/&quot;&gt;Debian Administrator&amp;#39;s Handbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Man_page&quot;&gt;&lt;code&gt;man&lt;/code&gt; command (Your local Linux system&amp;#39;s manual pages, e.g., &lt;code&gt;man ls&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials?q=linux+basics&quot;&gt;DigitalOcean Community Tutorials - Linux Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tecmint.com/&quot;&gt;TecMint - Linux How-To Guides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://explainshell.com/&quot;&gt;Explain Shell - Write a command to see the help text that matches each argument&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://training.linuxfoundation.org/&quot;&gt;Linux Foundation - Training &amp;amp; Certification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ryanstutorials.net/linuxtutorial/&quot;&gt;Ryan&amp;#39;s Tutorials - Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ss64.com/bash/&quot;&gt;SS64 Command line reference - Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linuxize.com/&quot;&gt;Linuxize - Linux Howtos, Tutorials &amp;amp; Guides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Linux</category><category>Command Line Interface</category><category>Operating Systems</category><category>System Administration</category><category>Developer Tools</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0007-introduction-to-linux-cli/hero.jpg" length="0" type="image/jpeg"/></item><item><title>How To Create A Custom VPC Using AWS CLI</title><link>https://mkabumattar.com/blog/post/how-to-create-a-custom-vpc-using-aws-cli/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/how-to-create-a-custom-vpc-using-aws-cli/</guid><description>In the sample that follows, an IPv4 CIDR block, a public subnet, and a private subnet are all created using AWS CLI instructions. You can run an instance in the public subnet and connect to it once the VPC and subnets have been configured. Additionally, you may start an instance on the private subnet and link to it from the instance on the public network.</description><pubDate>Sat, 15 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the sample that follows, an IPv4 CIDR block, a public subnet, and a private subnet are all created using AWS CLI instructions. You can run an instance in the public subnet and connect to it once the VPC and subnets have been configured. Additionally, you may start an instance on the private subnet and link to it from the instance on the public network.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI&lt;/li&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Configure AWS CLI: &lt;code&gt;aws configure&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Configure AWS CLI

aws configure

#AWS Access Key ID [None]: # Enter your access key here
#AWS Secret Access Key [None]: # Enter your secret key here
#Default region name [None]: # Enter your region here
#Default output format [None]: # Enter your output format here
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create a VPC&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get help for aws commands

aws help

# aws [COMMAND] [SUB-COMMAND] help

aws ec2 create-vpc help

# Create a VPC

AWS_VPC_INFO=$(aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--query &amp;#39;Vpc.{VpcId:VpcId}&amp;#39; \
--output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Modify your custom VPC and enable DNS hostname support&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Modify your custom VPC and enable DNS hostname support

aws ec2 modify-vpc-attribute \
--vpc-id $AWS_VPC_INFO \
--enable-dns-hostnames &amp;quot;{\&amp;quot;Value\&amp;quot;:true}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create a public subnet&lt;/h2&gt;
&lt;Notice type=&quot;note&quot;&gt;
  Availability zones: `us-east-1a`, `us-east-1b`, `us-east-1c`, `us-east-1d`,
  `us-east-1e`, `us-east-1f`.
&lt;/Notice&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a public subnet

AWS_SUBNET_PUBLIC=$(aws ec2 create-subnet \
--vpc-id $AWS_VPC_INFO --cidr-block 10.0.1.0/24 \
--availability-zone us-east-1a --query &amp;#39;Subnet.{SubnetId:SubnetId}&amp;#39; \
--output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Enable Auto-assign Public IP on the subnet&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Enable Auto-assign Public IP on the subnet

aws ec2 modify-subnet-attribute \
--subnet-id $AWS_SUBNET_PUBLIC \
--map-public-ip-on-launch
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create an Internet Gateway&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create an Internet Gateway

AWS_INTERNET_GATEWAY=$(aws ec2 create-internet-gateway \
--query &amp;#39;InternetGateway.{InternetGatewayId:InternetGatewayId}&amp;#39; \
--output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Attach the Internet gateway to your VPC&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Attach the Internet gateway to your VPC

aws ec2 attach-internet-gateway \
--vpc-id $AWS_VPC_INFO \
--internet-gateway-id $AWS_INTERNET_GATEWAY
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create a custom route table&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Create a custom route table

AWS_CUSTOM_ROUTE_TABLE=$(aws ec2 create-route-table \
--vpc-id $AWS_VPC_INFO \
--query &amp;#39;RouteTable.{RouteTableId:RouteTableId}&amp;#39; \
--output text )
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Associate the subnet with route table, making it a public subnet&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Associate the subnet with route table, making it a public subnet

AWS_ROUTE_TABLE_ASSOCITATION=$(aws ec2 associate-route-table  \
--subnet-id $AWS_SUBNET_PUBLIC \
--route-table-id $AWS_CUSTOM_ROUTE_TABLE \
--output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Get security group ID’s&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Get security group ID’s

AWS_DEFAULT_SECURITY_GROUP=$(aws ec2 describe-security-groups \
--filters &amp;quot;Name=vpc-id,Values=$AWS_VPC_INFO&amp;quot; \
--query &amp;#39;SecurityGroups[?GroupName == `default`].GroupId&amp;#39; \
--output text)

AWS_CUSTOM_SECURITY_GROUP=$(aws ec2 describe-security-groups \
--filters &amp;quot;Name=vpc-id,Values=$AWS_VPC_INFO&amp;quot; \
--query &amp;#39;SecurityGroups[?GroupName == `vpc-cli-lab-security-group`].GroupId&amp;#39; \
--output text)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Add tags to the resources in your VPC&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Add tags to the resources in your VPC

# Add a tag to the VPC

aws ec2 create-tags \
--resources $AWS_VPC_INFO \
--tags &amp;quot;Key=Name,Value=vpc-cli-lab&amp;quot;

# Add a tag to public subnet

aws ec2 create-tags \
--resources $AWS_SUBNET_PUBLIC \
--tags &amp;quot;Key=Name,Value=vpc-cli-lab-public-subnet&amp;quot;

# Add a tag to the Internet-Gateway

aws ec2 create-tags \
--resources $AWS_INTERNET_GATEWAY \
--tags &amp;quot;Key=Name,Value=vpc-cli-lab-internet-gateway&amp;quot;

# Add a tag to the default route table

AWS_DEFAULT_ROUTE_TABLE=$(aws ec2 describe-route-tables \
--filters &amp;quot;Name=vpc-id,Values=$AWS_VPC_INFO&amp;quot; \
--query &amp;#39;RouteTables[?Associations[0].Main != `flase`].RouteTableId&amp;#39; \
--output text)

aws ec2 create-tags \
--resources $AWS_DEFAULT_ROUTE_TABLE \
--tags &amp;quot;Key=Name,Value=vpc-cli-lab-default-route-table&amp;quot;

# Add a tag to the public route table

aws ec2 create-tags \
--resources $AWS_CUSTOM_ROUTE_TABLE \
--tags &amp;quot;Key=Name,Value=vpc-cli-lab-public-route-table&amp;quot;

# Add a tags to security groups

aws ec2 create-tags \
--resources $AWS_CUSTOM_SECURITY_GROUP \
--tags &amp;quot;Key=Name,Value=vpc-cli-lab-security-group&amp;quot;

aws ec2 create-tags \
--resources $AWS_DEFAULT_SECURITY_GROUP \
--tags &amp;quot;Key=Name,Value=vpc-cli-lab-default-security-group&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Delete the VPC (Cleanup)&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# Delete custom security group

aws ec2 delete-security-group \
--group-id $AWS_CUSTOM_SECURITY_GROUP

# Delete internet gateway
aws ec2 detach-internet-gateway \
--internet-gateway-id $AWS_INTERNET_GATEWAY \
--vpc-id $AWS_VPC_INFO

aws ec2 delete-internet-gateway \
--internet-gateway-id $AWS_INTERNET_GATEWAY

# Delete the custom route table

aws ec2 disassociate-route-table \
--association-id $AWS_ROUTE_TABLE_ASSOCITATION

aws ec2 delete-route-table \
--route-table-id $AWS_CUSTOM_ROUTE_TABLE

# Delete the public subnet

aws ec2 delete-subnet \
--subnet-id $AWS_SUBNET_PUBLIC

# Delete the vpc

aws ec2 delete-vpc \
--vpc-id $AWS_VPC_INFO
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html&quot;&gt;AWS CLI User Guide - Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html&quot;&gt;AWS CLI User Guide - Configuring the AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-vpc.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-vpc&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/modify-vpc-attribute.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 modify-vpc-attribute&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-subnet.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-subnet&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/modify-subnet-attribute.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 modify-subnet-attribute&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-internet-gateway.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-internet-gateway&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/attach-internet-gateway.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 attach-internet-gateway&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-route-table.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-route-table&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/associate-route-table.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 associate-route-table&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-security-groups.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 describe-security-groups&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-tags.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 create-tags&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/delete-security-group.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 delete-security-group&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/detach-internet-gateway.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 detach-internet-gateway&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/delete-vpc.html&quot;&gt;AWS CLI Command Reference - &lt;code&gt;ec2 delete-vpc&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AWS</category><category>VPC</category><category>AWS CLI</category><category>Cloud Networking</category><category>Infrastructure as Code</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0006-how-to-create-a-custom-vpc-using-aws-cli/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Setting up JWT Authentication in TypeScript with Express, MongoDB, Babel, Prettier, ESLint, and Husky - Part 2</title><link>https://mkabumattar.com/blog/post/setting-up-jwt-authentication-in-typescript-with-express-mongodb-babel-prettier-eslint-and-husky-part-2/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/setting-up-jwt-authentication-in-typescript-with-express-mongodb-babel-prettier-eslint-and-husky-part-2/</guid><description>Setting up JWT Authentication in Typescript with Express, MongoDB, Babel, Prettier, ESLint, and Husky: Part 2.</description><pubDate>Sun, 03 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Why do we even need an authentication mechanism in an application? in my opinion, it doesn&amp;#39;t need to be explained. The phrases authentication and authorization have likely crossed your lips, but I must emphasize that they have two distinct meanings.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Authentication: Any security approach must start with authentication, verifying that users are who they claim to be.&lt;/li&gt;
&lt;li&gt;Authorization: Authorization in the context of system security describes the procedure for authorizing user access to a certain resource or function. The words &amp;quot;access control&amp;quot; and &amp;quot;client privilege&amp;quot; are commonly used interchangeably.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the same time, the words &amp;quot;authentication&amp;quot; and &amp;quot;authorization&amp;quot; are used in the context of network security. In this context, authentication is the process of verifying that a user is who they claim to be. Authorization is the process of verifying that a user has the necessary rights to access a certain resource or function.&lt;/p&gt;
&lt;p&gt;We will learn how to create an authentication system using JWT in this tutorial. We will also learn how to create an authorization system using JWT with Typescript, Express. and the tutorial is a continuation of the previous tutorial.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/post/setting-up-node-js-express-prettier-eslint-and-husky-application-with-babel-and-typescript-part-1&quot;&gt;Setting up Node JS, Express, Prettier, ESLint and Husky Application with Babel and Typescript: Part 1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Directory and File Structure&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll start by creating a directory structure for our application, and then we&amp;#39;ll create a file structure for our application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;├── src
│   ├── bin
│   │   └── www.ts
│   ├── config
│   │   └── db.config.ts
│   ├── constants
│   │   ├── api.constant.ts
│   │   ├── dateformat.constant.ts
│   │   ├── http.code.constant.ts
│   │   ├── http.reason.constant.ts
│   │   ├── message.constant.ts
│   │   ├── model.constant.ts
│   │   ├── number.constant.ts
│   │   ├── path.constant.ts
│   │   └── regex.constant.ts
│   ├── controllers
│   │   ├── auth.controller.ts
│   │   └── user.controller.ts
│   ├── env
│   │   └── variable.env.ts
│   ├── interfaces
│   │   ├── controller.interface.ts
│   │   └── user.interface.ts
│   ├── middlewares
│   │   ├── authenticated.middleware.ts
│   │   ├── error.middleware.ts
│   │   └── validation.middleware.ts
│   ├── models
│   │   └── user.model.ts
│   ├── repositories
│   │   └── user.repository.ts
│   ├── schemas
│   │   └── user.schema.ts
│   ├── security
│   │   └── user.security.ts
│   ├── services
│   │   ├── auth.service.ts
│   │   └── user.service.ts
│   ├── types
│   │   └── express
│   │       └── index.d.ts
│   ├── utils
│   │   └── exceptions
│   │   │   └── http.exception.ts
│   │   └── logger.util.ts
│   └── validations
│       ├── token.validation.ts
│       ├── user.validation.ts
│       └── variable.validation.ts
├── .babelrc
├── .env
├── .env.example
├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .gitignore
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── commitlint.config.js
├── package.json
├── README.md
├── tsconfig.json
└── yarn.lock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&amp;#39;t be overwhelmed; this structure will be helpful after the program is finished and you start expanding the file structure for the business logic. This is just my opinion; perhaps you&amp;#39;ll organize the directory and files differently.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll be continuing build-up in the last tutorial &lt;a href=&quot;https://github.com/MKAbuMattar/template-express-typescript-blueprint/tree/part1&quot; target=&quot;__blank&quot;&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To better arrange the file structure and identify the key files, certain adjustments will be made to &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  ...,
  &amp;quot;paths&amp;quot;: {
    &amp;quot;@/bin/*&amp;quot;: [
      &amp;quot;bin/*&amp;quot;
    ],
    &amp;quot;@/config/*&amp;quot;: [
      &amp;quot;config/*&amp;quot;
    ],
    &amp;quot;@/constants/*&amp;quot;: [
      &amp;quot;constants/*&amp;quot;
    ],
    &amp;quot;@/controllers/*&amp;quot;: [
      &amp;quot;controllers/*&amp;quot;
    ],
    &amp;quot;@/env/*&amp;quot;: [
      &amp;quot;env/*&amp;quot;
    ],
    &amp;quot;@/interfaces/*&amp;quot;: [
      &amp;quot;interfaces/*&amp;quot;
    ],
    &amp;quot;@/middlewares/*&amp;quot;: [
      &amp;quot;middlewares/*&amp;quot;
    ],
    &amp;quot;@/models/*&amp;quot;: [
      &amp;quot;models/*&amp;quot;
    ],
    &amp;quot;@/repositories/*&amp;quot;: [
      &amp;quot;repositories/*&amp;quot;
    ],
    &amp;quot;@/routers/*&amp;quot;: [
      &amp;quot;routers/*&amp;quot;
    ],
    &amp;quot;@/schemas/*&amp;quot;: [
      &amp;quot;schemas/*&amp;quot;
    ],
    &amp;quot;@/security/*&amp;quot;: [
      &amp;quot;security/*&amp;quot;
    ],
    &amp;quot;@/services/*&amp;quot;: [
      &amp;quot;services/*&amp;quot;
    ],
    &amp;quot;@/utils/*&amp;quot;: [
      &amp;quot;utils/*&amp;quot;
    ],
    &amp;quot;@/validations/*&amp;quot;: [
      &amp;quot;validations/*&amp;quot;
    ],
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;nevertheless, in order to use the file structure, we must install a package called &lt;code&gt;module-alias&lt;/code&gt;. To install the package, use the following command after generating the project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add module-alias
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add -D @types/module-alias
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we need to do some change to &lt;code&gt;package.json&lt;/code&gt; and add &lt;code&gt;_moduleAliases&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  ...,
    &amp;quot;_moduleAliases&amp;quot;: {
    &amp;quot;@/bin&amp;quot;: &amp;quot;build/bin&amp;quot;,
    &amp;quot;@/config&amp;quot;: &amp;quot;build/config&amp;quot;,
    &amp;quot;@/constants&amp;quot;: &amp;quot;build/constants&amp;quot;,
    &amp;quot;@/controllers&amp;quot;: &amp;quot;build/controllers&amp;quot;,
    &amp;quot;@/env&amp;quot;: &amp;quot;build/env&amp;quot;,
    &amp;quot;@/interfaces&amp;quot;: &amp;quot;build/interfaces&amp;quot;,
    &amp;quot;@/middlewares&amp;quot;: &amp;quot;build/middlewares&amp;quot;,
    &amp;quot;@/models&amp;quot;: &amp;quot;build/models&amp;quot;,
    &amp;quot;@/repositories&amp;quot;: &amp;quot;build/repositories&amp;quot;,
    &amp;quot;@/routers&amp;quot;: &amp;quot;build/routers&amp;quot;,
    &amp;quot;@/schemas&amp;quot;: &amp;quot;build/schemas&amp;quot;,
    &amp;quot;@/security&amp;quot;: &amp;quot;build/security&amp;quot;,
    &amp;quot;@/services&amp;quot;: &amp;quot;build/services&amp;quot;,
    &amp;quot;@/utils&amp;quot;: &amp;quot;build/utils&amp;quot;,
    &amp;quot;@/validations&amp;quot;: &amp;quot;build/validations&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Environment Variables&lt;/h2&gt;
&lt;p&gt;A basic text configuration file called a &lt;code&gt;.env&lt;/code&gt; file or &lt;code&gt;dotenv&lt;/code&gt; file is used to manage the environment constants for your applications. The vast bulk of your application will remain the same throughout the Local, Staging, and Production environments. However, there are times when some configurations need to be changed between environments in various applications. Typical setup adjustments across contexts might be, but are not restricted to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;URL’s and API keys&lt;/li&gt;
&lt;li&gt;Domain names&lt;/li&gt;
&lt;li&gt;Public and private authentication keys&lt;/li&gt;
&lt;li&gt;Service account names&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An environment constant is a variable whose value is set outside to the application, generally via operating system capability. Any number of environment variables may be generated and made accessible for use at one time; each environment variable consists of a name/value pair.&lt;/p&gt;
&lt;p&gt;After creating the directory structure, we&amp;#39;ll create a file called &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;.env.example&lt;/code&gt; in the root directory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.env&lt;/code&gt;: This file will contain the configuration for the application.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env.example&lt;/code&gt;: is the file that contains all of the configurations for constants that &lt;code&gt;.env&lt;/code&gt; has, but without values; only this one is versioned. &lt;code&gt;env.example&lt;/code&gt; serves as a template for building a &lt;code&gt;.env&lt;/code&gt; file that contains the information required to start the program.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .env .env.example
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we add a new variable to &lt;code&gt;.env&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;NODE_ENV=development
# NODE_ENV=production
PORT=3030
DATABASE_URL=mongodb://127.0.0.1:27017/example

JWT_SECRET=secret
PASS_SECRET=secret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.env.example&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;NODE_ENV=development
# NODE_ENV=production
PORT=3030
DATABASE_URL=mongodb://

JWT_SECRET=secret
PASS_SECRET=secret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;They will now be loaded and used using the library &lt;code&gt;dotenv&lt;/code&gt;, and environment variables will be verified by a different library called &lt;code&gt;envalid&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add dotenv envalid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;variable.validation.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import {cleanEnv, str, port} from &amp;#39;envalid&amp;#39;;

const validate = (): void =&amp;gt; {
  cleanEnv(process.env, {
    NODE_ENV: str({
      choices: [&amp;#39;development&amp;#39;, &amp;#39;production&amp;#39;],
    }),
    PORT: port({default: 3030}),
    DATABASE_URL: str(),
    JWT_SECRET: str(),
    PASS_SECRET: str(),
  });
};

export default validate;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;variable.env.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import VariableValidate from &amp;#39;@/validations/variable.validation&amp;#39;;
import &amp;#39;dotenv/config&amp;#39;;

class Variable {
  public static readonly NODE_ENV: string = process.env.NODE_ENV!;

  public static readonly PORT: number = Number(process.env.PORT)!;

  public static readonly DATABASE_URL: string = process.env.DATABASE_URL!;

  public static readonly JWT_SECRET: string = process.env.JWT_SECRET!;

  public static readonly PASS_SECRET: string = process.env.PASS_SECRET!;

  constructor() {
    this.initialise();
  }

  private initialise(): void {
    VariableValidate();
  }
}

export default Variable;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Setup logger for development&lt;/h2&gt;
&lt;p&gt;I had a problem setting up the logger when constructing a server-side application based on Node and Express router. Conditions for the answer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Logging application event&lt;/li&gt;
&lt;li&gt;Ability to specify multiple logs level&lt;/li&gt;
&lt;li&gt;Logging of HTTP requests&lt;/li&gt;
&lt;li&gt;Ability to write logs into a different source (console and file)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I found two possible solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/morgan&quot;&gt;Morgan&lt;/a&gt;: HTTP logging middleware for express. It provides the ability to log incoming requests by specifying the formatting of log instance based on different request related information.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/winston&quot;&gt;Winston&lt;/a&gt;: Multiple types of transports are supported by a lightweight yet effective logging library. Because I want to simultaneously log events into a file and a terminal, this practical feature is crucial for me.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#39;ll use Winston for the logging, first I&amp;#39;ll install the package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add winston
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll begin by introducing the constants, which will be applied as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dateformat.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Dateformat {
  public static readonly YYYY_MM_DD_HH_MM_SS_MS: string =
    &amp;#39;YYYY-MM-DD HH:mm:ss:ms&amp;#39;;
}

export default Dateformat;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;path.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Path {
  public static readonly LOGS_ALL: string = &amp;#39;logs/all.log&amp;#39;;

  public static readonly LOGS_ERROR: string = &amp;#39;logs/error.log&amp;#39;;
}
export default Path;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll now create the &lt;code&gt;winston&lt;/code&gt; as a function to make it simpler to use:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;logger.util.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import ConstantDateFormat from &amp;#39;@/constants/dateformat.constant&amp;#39;;
import ConstantPath from &amp;#39;@/constants/path.constant&amp;#39;;
import Variable from &amp;#39;@/env/variable.env&amp;#39;;
import winston from &amp;#39;winston&amp;#39;;

const levels = {
  error: 0,
  warn: 1,
  info: 2,
  http: 3,
  debug: 4,
};

const level = () =&amp;gt; {
  const env = Variable.NODE_ENV || &amp;#39;development&amp;#39;;
  const isDevelopment = env === &amp;#39;development&amp;#39;;
  return isDevelopment ? &amp;#39;debug&amp;#39; : &amp;#39;warn&amp;#39;;
};

const colors = {
  error: &amp;#39;red&amp;#39;,
  warn: &amp;#39;yellow&amp;#39;,
  info: &amp;#39;green&amp;#39;,
  http: &amp;#39;magenta&amp;#39;,
  debug: &amp;#39;white&amp;#39;,
};

winston.addColors(colors);

const format = winston.format.combine(
  winston.format.timestamp({
    format: ConstantDateFormat.YYYY_MM_DD_HH_MM_SS_MS,
  }),
  winston.format.colorize({all: true}),
  winston.format.printf(
    (info) =&amp;gt; `${info.timestamp} ${info.level}: ${info.message}`,
  ),
);

const transports = [
  new winston.transports.Console(),
  new winston.transports.File({
    filename: ConstantPath.LOGS_ERROR,
    level: &amp;#39;error&amp;#39;,
  }),
  new winston.transports.File({filename: ConstantPath.LOGS_ALL}),
];

const logger = winston.createLogger({
  level: level(),
  levels,
  format,
  transports,
});

export default logger;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Setup MongoDB using Mongoose&lt;/h2&gt;
&lt;p&gt;What is MongoDB?&lt;/p&gt;
&lt;p&gt;MongoDB is a NoSQL database is used to store structured data. It is a document-oriented database made to operate with documents that resemble JSON.&lt;/p&gt;
&lt;p&gt;What is Mongoose?&lt;/p&gt;
&lt;p&gt;Mongoose is a MongoDB object modeling library. It is a MongoDB driver for Node.js.&lt;/p&gt;
&lt;p&gt;first I&amp;#39;ll install the package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add mongoose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll begin setting up the &lt;code&gt;mongoose&lt;/code&gt; to connect to the database right away:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;db.config.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import logger from &amp;#39;@/utils/logger.util&amp;#39;;
import {connect} from &amp;#39;mongoose&amp;#39;;

const connectDb = async (URL: string) =&amp;gt; {
  try {
    const connection: any = await connect(URL);
    logger.info(`Mongo DB is connected to: ${connection.connection.host}`);
  } catch (err) {
    logger.error(`An error ocurred\n\r\n\r${err}`);
  }
};

export default connectDb;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;after that, we&amp;#39;ll do some changes to &lt;code&gt;index.ts&lt;/code&gt;, which is the entry point of the application:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import connectDb from &amp;#39;@/config/db.config&amp;#39;;
// api constant
import ConstantAPI from &amp;#39;@/constants/api.constant&amp;#39;;
// http constant
import ConstantHttpCode from &amp;#39;@/constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;@/constants/http.reason.constant&amp;#39;;
// message constant
import ConstantMessage from &amp;#39;@/constants/message.constant&amp;#39;;
// variable
import Variable from &amp;#39;@/env/variable.env&amp;#39;;
import Controller from &amp;#39;@/interfaces/controller.interface&amp;#39;;
import ErrorMiddleware from &amp;#39;@/middlewares/error.middleware&amp;#39;;
import HttpException from &amp;#39;@/utils/exceptions/http.exception&amp;#39;;
import compression from &amp;#39;compression&amp;#39;;
import cookieParser from &amp;#39;cookie-parser&amp;#39;;
import cors from &amp;#39;cors&amp;#39;;
import express, {Application, Request, Response, NextFunction} from &amp;#39;express&amp;#39;;
import helmet from &amp;#39;helmet&amp;#39;;

class App {
  public app: Application;
  private DATABASE_URL: string;

  constructor(controllers: Controller[]) {
    this.app = express();
    this.DATABASE_URL = Variable.DATABASE_URL;

    this.initialiseDatabaseConnection(this.DATABASE_URL);
    this.initialiseConfig();
    this.initialiseRoutes();
    this.initialiseControllers(controllers);
    this.initialiseErrorHandling();
  }

  private initialiseConfig(): void {
    this.app.use(express.json());
    this.app.use(express.urlencoded({extended: true}));
    this.app.use(cookieParser());
    this.app.use(compression());
    this.app.use(cors());
    this.app.use(helmet());
  }

  private initialiseRoutes(): void {
    this.app.get(
      ConstantAPI.ROOT,
      (_req: Request, res: Response, next: NextFunction) =&amp;gt; {
        try {
          return res.status(ConstantHttpCode.OK).json({
            status: {
              code: ConstantHttpCode.OK,
              msg: ConstantHttpReason.OK,
            },
            msg: ConstantMessage.API_WORKING,
          });
        } catch (err: any) {
          return next(
            new HttpException(
              ConstantHttpCode.INTERNAL_SERVER_ERROR,
              ConstantHttpReason.INTERNAL_SERVER_ERROR,
              err.message,
            ),
          );
        }
      },
    );
  }

  private initialiseControllers(controllers: Controller[]): void {
    controllers.forEach((controller: Controller) =&amp;gt; {
      this.app.use(ConstantAPI.API, controller.router);
    });
  }

  private initialiseErrorHandling(): void {
    this.app.use(ErrorMiddleware);
  }

  private initialiseDatabaseConnection(url: string): void {
    connectDb(url);
  }
}

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will now begin to construct the user schema, but before we do, we must include constants for numbers:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;number.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Number {
  // user
  public static readonly USERNAME_MIN_LENGTH: number = 3;
  public static readonly USERNAME_MAX_LENGTH: number = 20;
  public static readonly NAME_MIN_LENGTH: number = 3;
  public static readonly NAME_MAX_LENGTH: number = 80;
  public static readonly EMAIL_MAX_LENGTH: number = 50;
  public static readonly PASSWORD_MIN_LENGTH: number = 8;
  public static readonly PHONE_MIN_LENGTH: number = 10;
  public static readonly PHONE_MAX_LENGTH: number = 20;
  public static readonly ADDRESS_MIN_LENGTH: number = 10;
  public static readonly ADDRESS_MAX_LENGTH: number = 200;
}

export default Number;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;user.schema.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import ConstantNumber from &amp;#39;@/constants/number.constant&amp;#39;;
import mongoose from &amp;#39;mongoose&amp;#39;;

const UserSchema = new mongoose.Schema(
  {
    username: {
      type: String,
      required: true,
      unique: true,
      min: ConstantNumber.USERNAME_MIN_LENGTH,
      max: ConstantNumber.USERNAME_MAX_LENGTH,
    },
    name: {
      type: String,
      required: true,
      min: ConstantNumber.NAME_MIN_LENGTH,
      max: ConstantNumber.NAME_MAX_LENGTH,
    },
    email: {
      type: String,
      required: true,
      unique: true,
      max: ConstantNumber.EMAIL_MAX_LENGTH,
    },
    password: {
      type: String,
      required: true,
      min: ConstantNumber.PASSWORD_MIN_LENGTH,
    },
    phone: {
      type: String,
      required: true,
      unique: true,
      min: ConstantNumber.PHONE_MIN_LENGTH,
      max: ConstantNumber.PHONE_MAX_LENGTH,
    },
    address: {
      type: String,
      required: true,
      min: ConstantNumber.ADDRESS_MIN_LENGTH,
      max: ConstantNumber.ADDRESS_MAX_LENGTH,
    },
    isAdmin: {
      type: Boolean,
      default: true,
    },
  },
  {
    versionKey: false,
    timestamps: true,
  },
);

export default UserSchema;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we must create a model in order to interact with this schema:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;model.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Model {
  public static readonly USER_MODEL: string = &amp;#39;UserModel&amp;#39;;
}

export default Model;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;user.interface.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import {Document} from &amp;#39;mongoose&amp;#39;;

export default interface User extends Document {
  username: string;
  name: string;
  email: string;
  password: string;
  phone: string;
  address: string;
  isAdmin: boolean;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;user.model.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import ConstantModel from &amp;#39;@/constants/model.constant&amp;#39;;
import UserInterface from &amp;#39;@/interfaces/user.interface&amp;#39;;
import UserSchema from &amp;#39;@/schemas/user.schema&amp;#39;;
import mongoose from &amp;#39;mongoose&amp;#39;;

const UserModel = mongoose.model&amp;lt;UserInterface&amp;gt;(
  ConstantModel.USER_MODEL,
  UserSchema,
);

export default UserModel;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my opinion, I build a file to handle all queries in the database through a specific cluster.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;user.repository.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import UserInterface from &amp;#39;@/interfaces/user.interface&amp;#39;;
import User from &amp;#39;@/models/user.model&amp;#39;;

class UserRepository {
  public async findAll(): Promise&amp;lt;UserInterface[]&amp;gt; {
    const users = await User.find({}).select(&amp;#39;-password&amp;#39;);
    return users;
  }

  public async findById(id: string): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findById(id).select(&amp;#39;-password&amp;#39;);
    return user;
  }

  public async findByUsername(username: string): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findOne({username}).select(&amp;#39;-password&amp;#39;);
    return user;
  }

  public async findByEmail(email: string): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findOne({email}).select(&amp;#39;-password&amp;#39;);
    return user;
  }

  public async findByPhone(phone: string): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findOne({phone}).select(&amp;#39;-password&amp;#39;);
    return user;
  }

  public async findByIdWithPassword(id: string): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findById(id);
    return user;
  }

  public async findByUsernameWithPassword(
    username: string,
  ): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findOne({username});
    return user;
  }

  public async findByEmailWithPassword(
    email: string,
  ): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findOne({email});
    return user;
  }

  public async findByPhoneWithPassword(
    phone: string,
  ): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findOne({phone});
    return user;
  }

  public async createUser(user: any): Promise&amp;lt;UserInterface | null&amp;gt; {
    const newUser = new User({
      username: user.username,
      name: user.name,
      email: user.email,
      password: user.password,
      phone: user.phone,
      address: user.address,
      isAdmin: user.isAdmin,
    });
    const savedUser = await newUser.save();
    return savedUser;
  }

  public async updateUsername(
    id: string,
    username: string,
  ): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findByIdAndUpdate(
      id,
      {username},
      {new: true},
    ).select(&amp;#39;-password&amp;#39;);
    return user;
  }

  public async updateName(
    id: string,
    name: string,
  ): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findByIdAndUpdate(id, {name}, {new: true}).select(
      &amp;#39;-password&amp;#39;,
    );
    return user;
  }

  public async updateEmail(
    id: string,
    email: string,
  ): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findByIdAndUpdate(id, {email}, {new: true}).select(
      &amp;#39;-password&amp;#39;,
    );
    return user;
  }

  public async updatePassword(
    id: string,
    password: string,
  ): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findByIdAndUpdate(
      id,
      {password},
      {new: true},
    ).select(&amp;#39;-password&amp;#39;);
    return user;
  }

  public async updatePhone(
    id: string,
    phone: string,
  ): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findByIdAndUpdate(id, {phone}, {new: true}).select(
      &amp;#39;-password&amp;#39;,
    );
    return user;
  }

  public async updateAddress(
    id: string,
    address: string,
  ): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findByIdAndUpdate(
      id,
      {address},
      {new: true},
    ).select(&amp;#39;-password&amp;#39;);
    return user;
  }

  public async deleteUser(id: string): Promise&amp;lt;UserInterface | null&amp;gt; {
    const user = await User.findByIdAndDelete(id);
    return user;
  }

  public async getUsersStats(lastYear: Date): Promise&amp;lt;UserInterface[] | null&amp;gt; {
    const users = await User.aggregate([
      {$match: {createdAt: {$gte: lastYear}}},
      {
        $project: {
          month: {$month: &amp;#39;$createdAt&amp;#39;},
        },
      },
      {
        $group: {
          _id: &amp;#39;$month&amp;#39;,
          total: {$sum: 1},
        },
      },
    ]);
    return users;
  }
}

export default UserRepository;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Setup Validation using Joi&lt;/h2&gt;
&lt;p&gt;What is Joi?&lt;/p&gt;
&lt;p&gt;Joi is a library that helps you validate data. It is a great tool to validate data before you save it to the database.&lt;/p&gt;
&lt;p&gt;first I&amp;#39;ll install the package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add joi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;regex.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Regex {
  public static readonly USERNAME = /^(?!.*\.\.)(?!.*\.$)[^\W][\w.]{3,32}$/;
  public static readonly EMAIL =
    /^(([^&amp;lt;&amp;gt;()\\[\]\\.,;:\s@&amp;quot;]+(\.[^&amp;lt;&amp;gt;()\\[\]\\.,;:\s@&amp;quot;]+)*)|(&amp;quot;.+&amp;quot;))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  public static readonly PASSWORD =
    /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&amp;amp;])[A-Za-z\d@$!%*?&amp;amp;]{8,}$/;
  public static readonly NAME = /^[a-zA-Z ]{2,35}$/;
  public static readonly PHONE =
    /^\s*(?:\+?(\d{1,3}))?([-. (]*(\d{3})[-. )]*)?((\d{3})[-. ]*(\d{2,4})(?:[-.x ]*(\d+))?)\s*$/;
  public static readonly ADDRESS = /^[a-zA-Z0-9\s,&amp;#39;-]{10,200}$/;
}

export default Regex;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;user.validation.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import ConstantRegex from &amp;#39;@/constants/regex.constant&amp;#39;;
import Joi from &amp;#39;joi&amp;#39;;

class UserValidation {
  public register = Joi.object({
    username: Joi.string().max(30).required(),
    name: Joi.string().max(30).required(),
    email: Joi.string().email().required(),
    password: Joi.string().min(6).max(30).required(),
    phone: Joi.string().min(10).max(15).required(),
    address: Joi.string().max(100).required(),
  });

  public login = Joi.object({
    email: Joi.string().email().required(),
    password: Joi.string().min(6).max(30).required(),
  });

  public updateUsername = Joi.object({
    username: Joi.string().max(30).required(),
    password: Joi.string().min(6).max(30).required(),
  });

  public updateName = Joi.object({
    name: Joi.string().max(30).required(),
    password: Joi.string().min(6).max(30).required(),
  });

  public updateEmail = Joi.object({
    email: Joi.string().email().required(),
    password: Joi.string().min(6).max(30).required(),
  });

  public updatePassword = Joi.object({
    oldPassword: Joi.string().min(6).max(30).required(),
    newPassword: Joi.string().min(6).max(30).required(),
    confirmPassword: Joi.string().min(6).max(30).required(),
  });

  public updatePhone = Joi.object({
    phone: Joi.string().min(10).max(15).required(),
    password: Joi.string().min(6).max(30).required(),
  });

  public updateAddress = Joi.object({
    address: Joi.string().max(100).required(),
    password: Joi.string().min(6).max(30).required(),
  });

  public deleteUser = Joi.object({
    password: Joi.string().min(6).max(30).required(),
  });

  public validateUsername(username: string): boolean {
    return ConstantRegex.USERNAME.test(username);
  }

  public validateName(name: string): boolean {
    return ConstantRegex.NAME.test(name);
  }

  public validateEmail(email: string): boolean {
    return ConstantRegex.EMAIL.test(email);
  }

  public validatePassword(password: string): boolean {
    return ConstantRegex.PASSWORD.test(password);
  }

  public validatePhone(phone: string): boolean {
    return ConstantRegex.PHONE.test(phone);
  }

  public validateAddress(address: string): boolean {
    return ConstantRegex.ADDRESS.test(address);
  }
}

export default UserValidation;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Setup JWT Authentication&lt;/h2&gt;
&lt;p&gt;What is JWT?&lt;/p&gt;
&lt;p&gt;JWT is a JSON Web Token. It is a standard for representing claims to be transferred between parties in a secure way.&lt;/p&gt;
&lt;p&gt;Alternatively explanation as a book&amp;#39;s:&lt;/p&gt;
&lt;p&gt;An open industry standard called JSON Web Token is used to exchange data between two entities, often a client (like the front end of your app) and a server (like the back end of your app). They include JSON objects that include the necessary information to be communicated. To ensure that the JSON contents, also known as JWT claims, cannot be changed by the client or an unintentional party, each JWT is additionally signed using cryptography (hashing).&lt;/p&gt;
&lt;p&gt;we need to install two libraries:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add jsonwebtoken crypto-js
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;jsonwebtoken&lt;/code&gt; is a library that helps you create, sign, and verify JSON Web Tokens.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crypto-js&lt;/code&gt; is a library that helps you encrypt and decrypt data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;we need to install the types for the library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add @types/jsonwebtoken @types/crypto-js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to encrypt, decode, and produce an access token, create a file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;user.security.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import Variable from &amp;#39;@/env/variable.env&amp;#39;;
import CryptoJS from &amp;#39;crypto-js&amp;#39;;
import jwt from &amp;#39;jsonwebtoken&amp;#39;;

class UserSecurity {
  public encrypt(password: string): string {
    return CryptoJS.AES.encrypt(password, Variable.PASS_SECRET).toString();
  }

  public decrypt(password: string): string {
    return CryptoJS.AES.decrypt(password, Variable.PASS_SECRET).toString(
      CryptoJS.enc.Utf8,
    );
  }

  public comparePassword(password: string, decryptedPassword: string): boolean {
    return password === this.decrypt(decryptedPassword);
  }

  public generateAccessToken(id: string, isAdmin: boolean): string {
    const token = jwt.sign({id, isAdmin}, Variable.JWT_SECRET, {
      expiresIn: &amp;#39;3d&amp;#39;,
    });

    return `Bearer ${token}`;
  }
}

export default UserSecurity;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;message.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Message {
  ...

  // auth
  public static readonly USERNAME_NOT_VALID: string = &amp;#39;username is not valid&amp;#39;
  public static readonly NAME_NOT_VALID: string = &amp;#39;name is not valid&amp;#39;
  public static readonly EMAIL_NOT_VALID: string = &amp;#39;email is not valid&amp;#39;
  public static readonly PASSWORD_NOT_VALID: string = &amp;#39;password is not valid&amp;#39;
  public static readonly PHONE_NOT_VALID: string = &amp;#39;phone is not valid&amp;#39;
  public static readonly ADDRESS_NOT_VALID: string = &amp;#39;address is not valid&amp;#39;
  public static readonly USERNAME_EXIST: string = &amp;#39;username is exist&amp;#39;
  public static readonly EMAIL_EXIST: string = &amp;#39;email is exist&amp;#39;
  public static readonly PHONE_EXIST: string = &amp;#39;phone is exist&amp;#39;
  public static readonly USER_NOT_CREATE: string =
    &amp;#39;user is not create, please try again&amp;#39;
  public static readonly USER_CREATE_SUCCESS: string =
    &amp;#39;user is create success, please login&amp;#39;
  public static readonly USER_NOT_FOUND: string = &amp;#39;user is not found&amp;#39;
  public static readonly PASSWORD_NOT_MATCH: string = &amp;#39;password is not match&amp;#39;
  public static readonly USER_LOGIN_SUCCESS: string = &amp;#39;user is login success&amp;#39;
}
export default Message
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;using the user validation form joi as input, construct middleware:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;validation.middleware.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// http constant
import ConstantHttpCode from &amp;#39;@/constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;@/constants/http.reason.constant&amp;#39;;
import {Request, Response, NextFunction, RequestHandler} from &amp;#39;express&amp;#39;;
import Joi from &amp;#39;joi&amp;#39;;

const validationMiddleware = (schema: Joi.Schema): RequestHandler =&amp;gt; {
  return async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;void&amp;gt; =&amp;gt; {
    const validationOptions = {
      abortEarly: false,
      allowUnknown: true,
      stripUnknown: true,
    };

    try {
      const value = await schema.validateAsync(req.body, validationOptions);
      req.body = value;
      next();
    } catch (e: any) {
      const errors: string[] = [];
      e.details.forEach((error: Joi.ValidationErrorItem) =&amp;gt; {
        errors.push(error.message);
      });

      res.status(ConstantHttpCode.NOT_FOUND).send({
        status: {
          code: ConstantHttpCode.NOT_FOUND,
          msg: ConstantHttpReason.NOT_FOUND,
        },
        msg: errors,
      });
    }
  };
};

export default validationMiddleware;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll now link the repository, security, and a service for authentication:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;auth.service.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import UserRepository from &amp;#39;@/repositories/user.repository&amp;#39;;
import UserSecurity from &amp;#39;@/security/user.security&amp;#39;;

class AuthService {
  private userRepository: UserRepository;
  private userSecurity: UserSecurity;

  constructor() {
    this.userRepository = new UserRepository();
    this.userSecurity = new UserSecurity();
  }

  public async findByUsername(username: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.findByUsername(username);
    return user;
  }

  public async findByEmail(email: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.findByEmail(email);
    return user;
  }

  public async findByPhone(phone: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.findByPhone(phone);
    return user;
  }

  public async findByEmailWithPassword(email: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.findByEmailWithPassword(email);
    return user;
  }

  public comparePassword(password: string, decryptedPassword: string): boolean {
    return this.userSecurity.comparePassword(password, decryptedPassword);
  }

  public async createUser(user: any): Promise&amp;lt;any&amp;gt; {
    const encryptedPassword = this.userSecurity.encrypt(user.password);
    const newUser = {
      username: user.username,
      name: user.name,
      email: user.email,
      password: encryptedPassword,
      phone: user.phone,
      address: user.address,
      isAdmin: user.isAdmin,
    };
    const savedUser = await this.userRepository.createUser(newUser);
    return savedUser;
  }

  public async generateAccessToken(
    id: string,
    isAdmin: boolean,
  ): Promise&amp;lt;string&amp;gt; {
    const token = this.userSecurity.generateAccessToken(id, isAdmin);
    return token;
  }
}

export default AuthService;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;api.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Api {
  ...

  // auth
  public static readonly AUTH_REGISTER: string = &amp;#39;/register&amp;#39;
  public static readonly AUTH_LOGIN: string = &amp;#39;/login&amp;#39;
}
export default Api
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;auth.controller.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// api constant
import ConstantAPI from &amp;#39;@/constants/api.constant&amp;#39;;
// http constant
import ConstantHttpCode from &amp;#39;@/constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;@/constants/http.reason.constant&amp;#39;;
// message constant
import ConstantMessage from &amp;#39;@/constants/message.constant&amp;#39;;
import Controller from &amp;#39;@/interfaces/controller.interface&amp;#39;;
import validationMiddleware from &amp;#39;@/middlewares/validation.middleware&amp;#39;;
import AuthService from &amp;#39;@/services/auth.service&amp;#39;;
import HttpException from &amp;#39;@/utils/exceptions/http.exception&amp;#39;;
// logger
import logger from &amp;#39;@/utils/logger.util&amp;#39;;
import Validate from &amp;#39;@/validations/user.validation&amp;#39;;
import {Router, Request, Response, NextFunction} from &amp;#39;express&amp;#39;;

class AuthController implements Controller {
  public path: string;
  public router: Router;
  private authService: AuthService;
  private validate: Validate;

  constructor() {
    this.path = ConstantAPI.AUTH;
    this.router = Router();
    this.authService = new AuthService();
    this.validate = new Validate();

    this.initialiseRoutes();
  }

  private initialiseRoutes(): void {
    this.router.post(
      `${this.path}${ConstantAPI.AUTH_REGISTER}`,
      validationMiddleware(this.validate.register),
      this.register,
    );

    this.router.post(
      `${this.path}${ConstantAPI.AUTH_LOGIN}`,
      validationMiddleware(this.validate.login),
      this.login,
    );
  }

  private register = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {username, name, email, password, phone, address} = req.body;

      const usernameValidated = this.validate.validateUsername(username);
      if (!usernameValidated) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.USERNAME_NOT_VALID,
          ),
        );
      }
      logger.info(`username ${username} is valid`);

      const nameValidated = this.validate.validateName(name);
      if (!nameValidated) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.NAME_NOT_VALID,
          ),
        );
      }
      logger.info(`name ${name} is valid`);

      const emailValidated = this.validate.validateEmail(email);
      if (!emailValidated) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.EMAIL_NOT_VALID,
          ),
        );
      }
      logger.info(`email ${email} is valid`);

      const passwordValidated = this.validate.validatePassword(password);
      if (!passwordValidated) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }
      logger.info(`password ${password} is valid`);

      const phoneValidated = this.validate.validatePhone(phone);
      if (!phoneValidated) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.PHONE_NOT_VALID,
          ),
        );
      }
      logger.info(`phone ${phone} is valid`);

      const addressValidated = this.validate.validateAddress(address);
      if (!addressValidated) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.ADDRESS_NOT_VALID,
          ),
        );
      }
      logger.info(`address ${address} is valid`);

      const usernameCheck = await this.authService.findByUsername(username);
      if (usernameCheck) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.USERNAME_EXIST,
          ),
        );
      }

      const emailCheck = await this.authService.findByEmail(email);
      if (emailCheck) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.EMAIL_EXIST,
          ),
        );
      }

      const phoneCheck = await this.authService.findByPhone(phone);
      if (phoneCheck) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.PHONE_EXIST,
          ),
        );
      }

      const newUserData = {
        username,
        name,
        email,
        password,
        phone,
        address,
      };

      const user = await this.authService.createUser(newUserData);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.CONFLICT,
            ConstantHttpReason.CONFLICT,
            ConstantMessage.USER_NOT_CREATE,
          ),
        );
      }

      const newUser = {...user}._doc;

      logger.info({newUserpassword: newUser.password});

      delete newUser.password;

      logger.info({newUserpassword: newUser.password});

      return res.status(ConstantHttpCode.CREATED).json({
        status: {
          code: ConstantHttpCode.CREATED,
          msg: ConstantHttpReason.CREATED,
        },
        msg: ConstantMessage.USER_CREATE_SUCCESS,
        data: newUser,
      });
    } catch (err: any) {
      return next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err.message,
        ),
      );
    }
  };

  private login = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {email, password} = req.body;

      const emailValidated = this.validate.validateEmail(email);
      if (!emailValidated) {
        return next(
          new HttpException(
            ConstantHttpCode.INTERNAL_SERVER_ERROR,
            ConstantHttpReason.INTERNAL_SERVER_ERROR,
            ConstantMessage.EMAIL_NOT_VALID,
          ),
        );
      }
      logger.info(`email ${email} is valid`);

      const passwordValidated = this.validate.validatePassword(password);
      if (!passwordValidated) {
        return next(
          new HttpException(
            ConstantHttpCode.INTERNAL_SERVER_ERROR,
            ConstantHttpReason.INTERNAL_SERVER_ERROR,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }
      logger.info(`password ${password} is valid`);

      const user = await this.authService.findByEmailWithPassword(email);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.INTERNAL_SERVER_ERROR,
            ConstantHttpReason.INTERNAL_SERVER_ERROR,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }

      const isMatch = this.authService.comparePassword(password, user.password);
      if (!isMatch) {
        return next(
          new HttpException(
            ConstantHttpCode.INTERNAL_SERVER_ERROR,
            ConstantHttpReason.INTERNAL_SERVER_ERROR,
            ConstantMessage.PASSWORD_NOT_MATCH,
          ),
        );
      }

      const accessToken = await this.authService.generateAccessToken(
        user.id,
        user.isAdmin,
      );
      logger.info(`accessToken: ${accessToken}`);

      const newUser = {...user}._doc;

      logger.info({newUserpassword: newUser.password});

      delete newUser.password;

      logger.info({newUserpassword: newUser.password});

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.USER_LOGIN_SUCCESS,
        data: {
          user: newUser,
          accessToken,
        },
      });
    } catch (err: any) {
      return next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err.message,
        ),
      );
    }
  };
}

export default AuthController;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will now develop a validation for each JWT that we receive:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;token.validation.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// http constant
import ConstantHttpCode from &amp;#39;@/constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;@/constants/http.reason.constant&amp;#39;;
// message constant
import ConstantMessage from &amp;#39;@/constants/message.constant&amp;#39;;
// variable
import Variable from &amp;#39;@/env/variable.env&amp;#39;;
import HttpException from &amp;#39;@/utils/exceptions/http.exception&amp;#39;;
import {verifyToken} from &amp;#39;@/validations/token.validation&amp;#39;;
import {Request, Response, NextFunction} from &amp;#39;express&amp;#39;;
import jwt from &amp;#39;jsonwebtoken&amp;#39;;

export const verifyToken = async (
  req: Request,
  res: Response,
  next: NextFunction,
) =&amp;gt; {
  const bearer = req.headers.authorization;
  logger.info(`bearer: ${bearer}`);

  if (!bearer) {
    return next(
      new HttpException(
        ConstantHttpCode.UNAUTHORIZED,
        ConstantHttpReason.UNAUTHORIZED,
        ConstantMessage.TOKEN_NOT_VALID,
      ),
    );
  }

  if (!bearer || !bearer.startsWith(&amp;#39;Bearer &amp;#39;)) {
    return next(
      new HttpException(
        ConstantHttpCode.UNAUTHORIZED,
        ConstantHttpReason.UNAUTHORIZED,
        ConstantMessage.UNAUTHORIZED,
      ),
    );
  }

  const accessToken = bearer.split(&amp;#39;Bearer &amp;#39;)[1].trim();

  return jwt.verify(accessToken, Variable.JWT_SECRET, (err, user: any) =&amp;gt; {
    if (err) {
      res.status(ConstantHttpCode.FORBIDDEN).json({
        status: {
          code: ConstantHttpCode.FORBIDDEN,
          msg: ConstantHttpReason.FORBIDDEN,
        },
        msg: ConstantMessage.TOKEN_NOT_VALID,
      });
    }
    req.user = user;
    return next();
  });
};

export default {verifyToken};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before moving on, we must make a few adjustments to the configuration file and type in the typescript request:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.d.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import User from &amp;#39;@/interfaces/user.interface&amp;#39;;

declare global {
  namespace Express {
    export interface Request {
      user: User;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  ...,
  &amp;quot;typeRoots&amp;quot;: [
    &amp;quot;./src/types&amp;quot;,
    &amp;quot;./node_modules/@types&amp;quot;
  ],
  ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;message.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Message {
  ...

  // token
  public static readonly TOKEN_NOT_VALID: string = &amp;#39;Token not valid&amp;#39;
  public static readonly NOT_AUTHENTICATED: string = &amp;#39;Not authenticated&amp;#39;
  public static readonly UNAUTHORIZED: string = &amp;#39;Unauthorized&amp;#39;
  public static readonly NOT_ALLOWED: string = &amp;#39;Not allowed&amp;#39;
}
export default Message
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, we can develop middleware to check if the request has authorization for the same end point:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;authenticated.middleware.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// http constant
import ConstantHttpCode from &amp;#39;@/constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;@/constants/http.reason.constant&amp;#39;;
// message constant
import ConstantMessage from &amp;#39;@/constants/message.constant&amp;#39;;
import HttpException from &amp;#39;@/utils/exceptions/http.exception&amp;#39;;
import {verifyToken} from &amp;#39;@/validations/token.validation&amp;#39;;
import {Request, Response, NextFunction} from &amp;#39;express&amp;#39;;

class AuthenticatedMiddleware {
  public async verifyTokenAndAuthorization(
    req: Request,
    res: Response,
    next: NextFunction,
  ) {
    verifyToken(req, res, () =&amp;gt; {
      if (req?.user?.id === req?.params?.id || req?.user?.isAdmin) {
        return next();
      }

      return next(
        new HttpException(
          ConstantHttpCode.FORBIDDEN,
          ConstantHttpReason.FORBIDDEN,
          ConstantMessage.NOT_ALLOWED,
        ),
      );
    });
  }

  public async verifyTokenAndAdmin(
    req: Request,
    res: Response,
    next: NextFunction,
  ) {
    verifyToken(req, res, () =&amp;gt; {
      if (req?.user?.isAdmin) {
        return next();
      }

      return next(
        new HttpException(
          ConstantHttpCode.FORBIDDEN,
          ConstantHttpReason.FORBIDDEN,
          ConstantMessage.NOT_ALLOWED,
        ),
      );
    });
  }
}

export default AuthenticatedMiddleware;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’ll now link the repository, security, and service for user:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;user.service.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import UserRepository from &amp;#39;@/repositories/user.repository&amp;#39;;
import UserSecurity from &amp;#39;@/security/user.security&amp;#39;;

class UserService {
  private userRepository: UserRepository;
  private userSecurity: UserSecurity;

  constructor() {
    this.userRepository = new UserRepository();
    this.userSecurity = new UserSecurity();
  }

  public comparePassword(password: string, encryptedPassword: string): boolean {
    return this.userSecurity.comparePassword(password, encryptedPassword);
  }

  public async findAll(): Promise&amp;lt;any&amp;gt; {
    const users = await this.userRepository.findAll();
    return users;
  }

  public async findById(id: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.findById(id);
    return user;
  }

  public async findByUsername(username: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.findByUsername(username);
    return user;
  }

  public async findByEmail(email: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.findByEmail(email);
    return user;
  }

  public async findByPhone(phone: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.findByPhone(phone);
    return user;
  }

  public async findByIdWithPassword(id: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.findByIdWithPassword(id);
    return user;
  }

  public async updateUsername(id: string, username: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.updateUsername(id, username);
    return user;
  }

  public async updateName(id: string, name: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.updateName(id, name);
    return user;
  }

  public async updateEmail(id: string, email: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.updateEmail(id, email);
    return user;
  }

  public async updatePassword(id: string, password: string): Promise&amp;lt;any&amp;gt; {
    const encryptedPassword = this.userSecurity.encrypt(password);
    const user = await this.userRepository.updatePassword(
      id,
      encryptedPassword,
    );
    return user;
  }

  public async updatePhone(id: string, phone: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.updatePhone(id, phone);
    return user;
  }

  public async updateAddress(id: string, address: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.updateAddress(id, address);
    return user;
  }

  public async deleteUser(id: string): Promise&amp;lt;any&amp;gt; {
    const user = await this.userRepository.deleteUser(id);
    return user;
  }

  public async getUsersStats(): Promise&amp;lt;any&amp;gt; {
    const date = new Date();
    const lastYear = new Date(date.setFullYear(date.getFullYear() - 1));
    const usersStats = await this.userRepository.getUsersStats(lastYear);
    return usersStats;
  }
}

export default UserService;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;api.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Api {
  ...

  // users
  public static readonly USER_UPDATE_USERNAME: string = &amp;#39;/update-username/:id&amp;#39;
  public static readonly USER_UPDATE_NAME: string = &amp;#39;/update-name/:id&amp;#39;
  public static readonly USER_UPDATE_EMAIL: string = &amp;#39;/update-email/:id&amp;#39;
  public static readonly USER_UPDATE_PASSWORD: string = &amp;#39;/update-password/:id&amp;#39;
  public static readonly USER_UPDATE_PHONE: string = &amp;#39;/update-phone/:id&amp;#39;
  public static readonly USER_UPDATE_ADDRESS: string = &amp;#39;/update-address/:id&amp;#39;
  public static readonly USER_DELETE: string = &amp;#39;/delete/:id&amp;#39;
  public static readonly USER_GET: string = &amp;#39;/find/:id&amp;#39;
  public static readonly USER_GET_ALL: string = &amp;#39;/&amp;#39;
  public static readonly USER_GET_ALL_STATS: string = &amp;#39;/stats&amp;#39;
}
export default Api
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;message.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Message {
  ...

  // user
  public static readonly USERNAME_NOT_CHANGE: string = &amp;#39;username is not change&amp;#39;
  public static readonly USERNAME_CHANGE_SUCCESS: string =
    &amp;#39;username is change success&amp;#39;
  public static readonly NAME_NOT_CHANGE: string = &amp;#39;name is not change&amp;#39;
  public static readonly NAME_CHANGE_SUCCESS: string = &amp;#39;name is change success&amp;#39;
  public static readonly EMAIL_NOT_CHANGE: string = &amp;#39;email is not change&amp;#39;
  public static readonly EMAIL_CHANGE_SUCCESS: string =
    &amp;#39;email is change success&amp;#39;
  public static readonly PASSWORD_NOT_CHANGE: string = &amp;#39;password is not change&amp;#39;
  public static readonly PASSWORD_CHANGE_SUCCESS: string =
    &amp;#39;password is change success&amp;#39;
  public static readonly PHONE_NOT_CHANGE: string = &amp;#39;phone is not change&amp;#39;
  public static readonly PHONE_CHANGE_SUCCESS: string =
    &amp;#39;phone is change success&amp;#39;
  public static readonly ADDRESS_NOT_CHANGE: string = &amp;#39;address is not change&amp;#39;
  public static readonly ADDRESS_CHANGE_SUCCESS: string =
    &amp;#39;address is change success&amp;#39;
  public static readonly USER_NOT_DELETE: string =
    &amp;#39;user is not delete, please try again&amp;#39;
  public static readonly USER_DELETE_SUCCESS: string = &amp;#39;user is delete success&amp;#39;
  public static readonly USER_FOUND: string = &amp;#39;user is found&amp;#39;
}
export default Message
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To access the service for what we need to build the methods, we&amp;#39;ll make a new contact with the middleware for each authorized user and input validation:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;user.controller.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// api constant
import ConstantAPI from &amp;#39;@/constants/api.constant&amp;#39;;
// http constant
import ConstantHttpCode from &amp;#39;@/constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;@/constants/http.reason.constant&amp;#39;;
// message constant
import ConstantMessage from &amp;#39;@/constants/message.constant&amp;#39;;
import Controller from &amp;#39;@/interfaces/controller.interface&amp;#39;;
import Authenticated from &amp;#39;@/middlewares/authenticated.middleware&amp;#39;;
import validationMiddleware from &amp;#39;@/middlewares/validation.middleware&amp;#39;;
import UserService from &amp;#39;@/services/user.service&amp;#39;;
import HttpException from &amp;#39;@/utils/exceptions/http.exception&amp;#39;;
// logger
import logger from &amp;#39;@/utils/logger.util&amp;#39;;
import Validate from &amp;#39;@/validations/user.validation&amp;#39;;
import {Router, Request, Response, NextFunction} from &amp;#39;express&amp;#39;;

class UserController implements Controller {
  public path: string;
  public router: Router;
  private userService: UserService;
  private authenticated: Authenticated;
  private validate: Validate;

  constructor() {
    this.path = ConstantAPI.USERS;
    this.router = Router();
    this.userService = new UserService();
    this.authenticated = new Authenticated();
    this.validate = new Validate();

    this.initialiseRoutes();
  }

  private initialiseRoutes(): void {
    this.router.post(
      `${this.path}${ConstantAPI.USER_UPDATE_USERNAME}`,
      this.authenticated.verifyTokenAndAuthorization,
      validationMiddleware(this.validate.updateUsername),
      this.updateUsername,
    );

    this.router.post(
      `${this.path}${ConstantAPI.USER_UPDATE_NAME}`,
      this.authenticated.verifyTokenAndAuthorization,
      validationMiddleware(this.validate.updateName),
      this.updateName,
    );

    this.router.post(
      `${this.path}${ConstantAPI.USER_UPDATE_EMAIL}`,
      this.authenticated.verifyTokenAndAuthorization,
      validationMiddleware(this.validate.updateEmail),
      this.updateEmail,
    );

    this.router.post(
      `${this.path}${ConstantAPI.USER_UPDATE_PASSWORD}`,
      this.authenticated.verifyTokenAndAuthorization,
      validationMiddleware(this.validate.updatePassword),
      this.updatePassword,
    );

    this.router.post(
      `${this.path}${ConstantAPI.USER_UPDATE_PHONE}`,
      this.authenticated.verifyTokenAndAuthorization,
      validationMiddleware(this.validate.updatePhone),
      this.updatePhone,
    );

    this.router.post(
      `${this.path}${ConstantAPI.USER_UPDATE_ADDRESS}`,
      this.authenticated.verifyTokenAndAuthorization,
      validationMiddleware(this.validate.updateAddress),
      this.updateAddress,
    );

    this.router.post(
      `${this.path}${ConstantAPI.USER_DELETE}`,
      this.authenticated.verifyTokenAndAuthorization,
      validationMiddleware(this.validate.deleteUser),
      this.deleteUser,
    );

    this.router.get(
      `${this.path}${ConstantAPI.USER_GET}`,
      this.authenticated.verifyTokenAndAuthorization,
      this.getUser,
    );

    this.router.get(
      `${this.path}${ConstantAPI.USER_GET_ALL}`,
      this.authenticated.verifyTokenAndAdmin,
      this.getAllUsers,
    );

    this.router.get(
      `${this.path}${ConstantAPI.USER_GET_ALL_STATS}`,
      this.authenticated.verifyTokenAndAdmin,
      this.getUsersStats,
    );
  }

  private updateUsername = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {username, password} = req.body;
      const {id} = req.params;

      const user = await this.userService.findByIdWithPassword(id);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }
      logger.info(`user ${user.username} found`);

      const isUsernameValid = this.validate.validateUsername(username);
      if (!isUsernameValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.USERNAME_NOT_VALID,
          ),
        );
      }
      logger.info(`username ${username} is valid`);

      const isPasswordValid = this.validate.validatePassword(password);
      if (!isPasswordValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }
      logger.info(`password ${password} is valid`);

      const isMatch = this.userService.comparePassword(password, user.password);
      if (!isMatch) {
        return next(
          new HttpException(
            ConstantHttpCode.UNAUTHORIZED,
            ConstantHttpReason.UNAUTHORIZED,
            ConstantMessage.PASSWORD_NOT_MATCH,
          ),
        );
      }
      logger.info(`password ${password} match`);

      const usernameCheck = await this.userService.findByUsername(username);
      if (usernameCheck) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.USERNAME_EXIST,
          ),
        );
      }

      if (user.username === username) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.USERNAME_NOT_CHANGE,
          ),
        );
      }

      const updatedUser = await this.userService.updateUsername(id, username);
      if (!updatedUser) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.USERNAME_NOT_CHANGE,
          ),
        );
      }
      logger.info(`user ${user.username} updated`);

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.USERNAME_CHANGE_SUCCESS,
        data: {
          user: updatedUser,
        },
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };

  private updateName = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {name, password} = req.body;
      const {id} = req.params;

      const user = await this.userService.findByIdWithPassword(id);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }
      logger.info(`user ${user.username} found`);

      const isNameValid = this.validate.validateName(name);
      if (!isNameValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.NAME_NOT_VALID,
          ),
        );
      }
      logger.info(`name ${name} is valid`);

      const isPasswordValid = this.validate.validatePassword(password);
      if (!isPasswordValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }
      logger.info(`password ${password} is valid`);

      const isMatch = this.userService.comparePassword(password, user.password);
      if (!isMatch) {
        return next(
          new HttpException(
            ConstantHttpCode.UNAUTHORIZED,
            ConstantHttpReason.UNAUTHORIZED,
            ConstantMessage.PASSWORD_NOT_MATCH,
          ),
        );
      }
      logger.info(`password ${password} match`);

      if (user.name === name) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.NAME_NOT_CHANGE,
          ),
        );
      }

      const updatedUser = await this.userService.updateName(id, name);
      if (!updatedUser) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.NAME_NOT_CHANGE,
          ),
        );
      }
      logger.info(`user ${user.username} updated`);

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.NAME_CHANGE_SUCCESS,
        data: {
          user: updatedUser,
        },
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };

  private updateEmail = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {email, password} = req.body;
      const {id} = req.params;

      const user = await this.userService.findByIdWithPassword(id);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }

      const isEmailValid = this.validate.validateEmail(email);
      if (!isEmailValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.EMAIL_NOT_VALID,
          ),
        );
      }

      const isPasswordValid = this.validate.validatePassword(password);
      if (!isPasswordValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }

      if (user.email === email) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.EMAIL_NOT_CHANGE,
          ),
        );
      }

      const emailCheck = await this.userService.findByEmail(email);
      if (emailCheck) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.EMAIL_EXIST,
          ),
        );
      }

      const isMatch = this.userService.comparePassword(password, user.password);
      if (!isMatch) {
        return next(
          new HttpException(
            ConstantHttpCode.UNAUTHORIZED,
            ConstantHttpReason.UNAUTHORIZED,
            ConstantMessage.PASSWORD_NOT_MATCH,
          ),
        );
      }

      const updatedUser = await this.userService.updateEmail(id, email);
      if (!updatedUser) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.EMAIL_NOT_CHANGE,
          ),
        );
      }

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.EMAIL_CHANGE_SUCCESS,
        data: {
          user: updatedUser,
        },
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };

  private updatePassword = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {oldPassword, newPassword, confirmPassword} = req.body;
      const {id} = req.params;

      if (newPassword !== confirmPassword) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_MATCH,
          ),
        );
      }

      const user = await this.userService.findByIdWithPassword(id);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }

      const isOldPasswordValid = this.validate.validatePassword(oldPassword);
      if (!isOldPasswordValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }

      const isNewPasswordValid = this.validate.validatePassword(newPassword);
      if (!isNewPasswordValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }

      const isConfirmPasswordValid =
        this.validate.validatePassword(confirmPassword);
      if (!isConfirmPasswordValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }

      const isMatch = this.userService.comparePassword(
        oldPassword,
        user.password,
      );
      if (!isMatch) {
        return next(
          new HttpException(
            ConstantHttpCode.UNAUTHORIZED,
            ConstantHttpReason.UNAUTHORIZED,
            ConstantMessage.PASSWORD_NOT_MATCH,
          ),
        );
      }

      if (oldPassword === newPassword) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_CHANGE,
          ),
        );
      }

      const updatedUser = await this.userService.updatePassword(
        id,
        newPassword,
      );
      if (!updatedUser) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_CHANGE,
          ),
        );
      }

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.PASSWORD_CHANGE_SUCCESS,
        data: {
          user: updatedUser,
        },
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };

  private updatePhone = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {phone, password} = req.body;
      const {id} = req.params;

      const user = await this.userService.findByIdWithPassword(id);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }

      const isPhoneValid = this.validate.validatePhone(phone);
      logger.info({isPhoneValid});
      if (!isPhoneValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PHONE_NOT_VALID,
          ),
        );
      }

      const isPasswordValid = this.validate.validatePassword(password);
      if (!isPasswordValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }

      const phoneCheck = await this.userService.findByPhone(phone);
      if (phoneCheck) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.PHONE_EXIST,
          ),
        );
      }

      const isMatch = this.userService.comparePassword(password, user.password);
      if (!isMatch) {
        return next(
          new HttpException(
            ConstantHttpCode.UNAUTHORIZED,
            ConstantHttpReason.UNAUTHORIZED,
            ConstantMessage.PASSWORD_NOT_MATCH,
          ),
        );
      }

      if (user.phone === phone) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PHONE_NOT_CHANGE,
          ),
        );
      }

      const updatedUser = await this.userService.updatePhone(id, phone);
      if (!updatedUser) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PHONE_NOT_CHANGE,
          ),
        );
      }

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.PHONE_CHANGE_SUCCESS,
        data: {
          user: updatedUser,
        },
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };

  private updateAddress = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {address, password} = req.body;
      const {id} = req.params;

      const user = await this.userService.findByIdWithPassword(id);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }

      const isAddressValid = this.validate.validateAddress(address);
      if (!isAddressValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.ADDRESS_NOT_VALID,
          ),
        );
      }

      const isPasswordValid = this.validate.validatePassword(password);
      if (!isPasswordValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }

      const isMatch = this.userService.comparePassword(password, user.password);
      if (!isMatch) {
        return next(
          new HttpException(
            ConstantHttpCode.UNAUTHORIZED,
            ConstantHttpReason.UNAUTHORIZED,
            ConstantMessage.PASSWORD_NOT_MATCH,
          ),
        );
      }

      if (user.address === address) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.ADDRESS_NOT_CHANGE,
          ),
        );
      }

      const updatedUser = await this.userService.updateAddress(id, address);
      if (!updatedUser) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.ADDRESS_NOT_CHANGE,
          ),
        );
      }

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.ADDRESS_CHANGE_SUCCESS,
        data: {
          user: updatedUser,
        },
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };

  private deleteUser = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {password} = req.body;
      const {id} = req.params;

      const user = await this.userService.findByIdWithPassword(id);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }

      const isPasswordValid = this.validate.validatePassword(password);
      if (!isPasswordValid) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.PASSWORD_NOT_VALID,
          ),
        );
      }

      const isMatch = this.userService.comparePassword(password, user.password);
      if (!isMatch) {
        return next(
          new HttpException(
            ConstantHttpCode.UNAUTHORIZED,
            ConstantHttpReason.UNAUTHORIZED,
            ConstantMessage.PASSWORD_NOT_MATCH,
          ),
        );
      }

      const deletedUser = await this.userService.deleteUser(id);
      if (!deletedUser) {
        return next(
          new HttpException(
            ConstantHttpCode.BAD_REQUEST,
            ConstantHttpReason.BAD_REQUEST,
            ConstantMessage.USER_NOT_DELETE,
          ),
        );
      }

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.USER_DELETE_SUCCESS,
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };

  private getUser = async (
    req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const {id} = req.params;

      const user = await this.userService.findById(id);
      if (!user) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.USER_FOUND,
        data: {
          user,
        },
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };

  private getAllUsers = async (
    _req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const users = await this.userService.findAll();
      if (!users) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.USER_FOUND,
        data: {
          users,
        },
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };

  private getUsersStats = async (
    _req: Request,
    res: Response,
    next: NextFunction,
  ): Promise&amp;lt;Response | void&amp;gt; =&amp;gt; {
    try {
      const usersStats = await this.userService.getUsersStats();
      if (!usersStats) {
        return next(
          new HttpException(
            ConstantHttpCode.NOT_FOUND,
            ConstantHttpReason.NOT_FOUND,
            ConstantMessage.USER_NOT_FOUND,
          ),
        );
      }

      return res.status(ConstantHttpCode.OK).json({
        status: {
          code: ConstantHttpCode.OK,
          msg: ConstantHttpReason.OK,
        },
        msg: ConstantMessage.USER_FOUND,
        data: {
          users: usersStats,
        },
      });
    } catch (err: any) {
      next(
        new HttpException(
          ConstantHttpCode.INTERNAL_SERVER_ERROR,
          ConstantHttpReason.INTERNAL_SERVER_ERROR,
          err?.message,
        ),
      );
    }
  };
}

export default UserController;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;api.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Api {
  ...

  public static readonly AUTH: string = `/auth`
  public static readonly USERS: string = &amp;#39;/users&amp;#39;
}
export default Api
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;after that, we&amp;#39;ll do some changes to the &lt;code&gt;www.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;www.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;#!/usr/bin/env ts-node
import App from &amp;#39;..&amp;#39;;
// controllers
import AuthController from &amp;#39;@/controllers/auth.controller&amp;#39;;
import UserController from &amp;#39;@/controllers/user.controller&amp;#39;;
import Variable from &amp;#39;@/env/variable.env&amp;#39;;
import logger from &amp;#39;@/utils/logger.util&amp;#39;;
import &amp;#39;core-js/stable&amp;#39;;
import http from &amp;#39;http&amp;#39;;
import &amp;#39;module-alias/register&amp;#39;;
import &amp;#39;regenerator-runtime/runtime&amp;#39;;

const {app} = new App([new AuthController(), new UserController()]);

/**
 * Normalize a port into a number, string, or false.
 */
const normalizePort = (val: any) =&amp;gt; {
  const port = parseInt(val, 10);

  if (Number.isNaN(port)) {
    // named pipe
    return val;
  }

  if (port &amp;gt;= 0) {
    // port number
    return port;
  }

  return false;
};

const port = normalizePort(Variable.PORT || &amp;#39;3030&amp;#39;);
app.set(&amp;#39;port&amp;#39;, port);

/**
 * Create HTTP server.
 */
const server = http.createServer(app);

/**
 * Event listener for HTTP server &amp;quot;error&amp;quot; event.
 */
const onError = (error: any) =&amp;gt; {
  if (error.syscall !== &amp;#39;listen&amp;#39;) {
    throw error;
  }

  const bind = typeof port === &amp;#39;string&amp;#39; ? `Pipe ${port}` : `Port ${port}`;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case &amp;#39;EACCES&amp;#39;:
      logger.error(`${bind} requires elevated privileges`);
      process.exit(1);
      break;
    case &amp;#39;EADDRINUSE&amp;#39;:
      logger.error(`${bind} is already in use`);
      process.exit(1);
      break;
    default:
      throw error;
  }
};

/**
 * Event listener for HTTP server &amp;quot;listening&amp;quot; event.
 */
const onListening = () =&amp;gt; {
  const addr = server.address();
  const bind = typeof addr === &amp;#39;string&amp;#39; ? `pipe ${addr}` : `port ${addr?.port}`;
  logger.info(`Listening on ${bind}`);
};

server.listen(port);
server.on(&amp;#39;error&amp;#39;, onError);
server.on(&amp;#39;listening&amp;#39;, onListening);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;All in all, you learnt about JWTs and how to develop a router-level middleware for JWT authentication in Node.js and Express.js using TypeScript. If we wanted to authenticate all incoming requests to our API, we could also utilize it as an application-level middleware.&lt;/p&gt;
&lt;p&gt;All code from this tutorial as a complete package is available in this &lt;a href=&quot;https://github.com/MKAbuMattar/template-express-typescript-blueprint/tree/part2&quot; target=&quot;__blank&quot;&gt;repository&lt;/a&gt;. If you find this tutorial helpful, please share it with your friends and colleagues, and make sure to star the &lt;a href=&quot;https://github.com/MKAbuMattar/template-express-typescript-blueprint/tree/part2&quot; target=&quot;__blank&quot;&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/post/setting-up-node-js-express-prettier-eslint-and-husky-application-with-babel-and-typescript-part-1&quot;&gt;Setting up Node JS, Express, Prettier, ESLint and Husky Application with Babel and Typescript: Part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jwt.io/&quot;&gt;JSON Web Tokens (JWT) Official Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://expressjs.com/&quot;&gt;Express.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/&quot;&gt;MongoDB Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mongoosejs.com/&quot;&gt;Mongoose ODM Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/&quot;&gt;Prettier Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://typicode.github.io/husky/&quot;&gt;Husky Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hapijs/joi&quot;&gt;Joi Validation Library (GitHub)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/jsonwebtoken&quot;&gt;jsonwebtoken (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/crypto-js&quot;&gt;crypto-js (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/winstonjs/winston&quot;&gt;Winston Logger (GitHub)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/dotenv&quot;&gt;dotenv (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/envalid&quot;&gt;envalid (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/module-alias&quot;&gt;module-alias (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Backend Development</category><category>Node.js</category><category>TypeScript</category><category>Authentication</category><category>API Development</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0004-setting-up-node-js-express-prettier-eslint-and-husky-application-with-babel-and-typescript/hero.jpg" length="0" type="image/jpeg"/></item><item><title>Setting up Node.js, Express, Prettier, ESLint, and Husky application with Babel and TypeScript - Part 1</title><link>https://mkabumattar.com/blog/post/setting-up-node-js-express-prettier-eslint-and-husky-application-with-babel-and-typescript-part-1/</link><guid isPermaLink="true">https://mkabumattar.com/blog/post/setting-up-node-js-express-prettier-eslint-and-husky-application-with-babel-and-typescript-part-1/</guid><description>Setting up Node JS, Express,  Prettier, ESLint and Husky Application with Babel and Typescript: Part 1.</description><pubDate>Fri, 01 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;All code from this tutorial as a complete package is available in this &lt;a href=&quot;https://github.com/MKAbuMattar/template-express-typescript-blueprint/tree/part1&quot; target=&quot;__blank&quot;&gt;repository&lt;/a&gt;. If you find this tutorial helpful, please share it with your friends and colleagues, and make sure to star the repository.&lt;/p&gt;
&lt;p&gt;So, in this little tutorial, I’ll explain how to set up babel for a basic NodeJS Express, and typescript application so that we may utilize the most recent ES6 syntax in it.&lt;/p&gt;
&lt;h2&gt;What is TypeScript?&lt;/h2&gt;
&lt;a href=&quot;http://www.typescriptlang.org/&quot; target=&quot;__blank&quot;&gt;
  TypeScript
&lt;/a&gt;
is a superset of JavaScript that mainly offers classes, interfaces, and optional
static typing. The ability to enable IDEs to give a richer environment for
seeing typical mistakes as you enter the code is one of the major advantages.&lt;ul&gt;
&lt;li&gt;JavaScript and More: TypeScript adds additional syntax to JavaScript to support a &lt;strong&gt;tighter integration with your editor&lt;/strong&gt;. Catch errors early in your editor.&lt;/li&gt;
&lt;li&gt;A Result You Can Trust: TypeScript code converts to JavaScript, which &lt;strong&gt;runs anywhere JavaScript runs&lt;/strong&gt;: In a browser, on Node.js or Deno and in your apps.&lt;/li&gt;
&lt;li&gt;Safety at Scale: TypeScript understands JavaScript and uses &lt;strong&gt;type inference to give you great tooling&lt;/strong&gt; without additional code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is Babel?&lt;/h2&gt;
&lt;a href=&quot;https://babeljs.io/&quot; target=&quot;__blank&quot;&gt;
  Babel
&lt;/a&gt;
Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a
backwards compatible version of JavaScript in current and older browsers or
environments. Here are the main things Babel can do for you:&lt;ul&gt;
&lt;li&gt;Transform syntax&lt;/li&gt;
&lt;li&gt;Polyfill features that are missing in your target environment (through a third-party polyfill such as core-js)&lt;/li&gt;
&lt;li&gt;Source code transformations (codemods)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Project Setup&lt;/h2&gt;
&lt;p&gt;We’ll begin by creating a new directory called &lt;code&gt;template-express-typescript-blueprint&lt;/code&gt; and then we’ll create a new package.json file. We’re going to be using yarn for this example, but you could just as easily use NPM if you choose, but yarn is a lot more convenient.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mkdir template-express-typescript-blueprint
cd template-express-typescript-blueprint
yarn init -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we&amp;#39;ll connect to our new project with git.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A new Git repository is created with the git init command. It may be used to start a fresh, empty repository or convert an existing, unversioned project to a Git repository. This is often the first command you&amp;#39;ll perform in a new project because the majority of additional Git commands are not accessible outside of an initialized repository.&lt;/p&gt;
&lt;p&gt;Now we&amp;#39;ll connect to our new project with github, creating a new empty repository, after we&amp;#39;ve created a new directory called &lt;code&gt;template-express-typescript-blueprint&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;echo &amp;quot;# Setting up Node JS, Express,  Prettier, ESLint and Husky Application with Babel and Typescript: Part 1&amp;quot; &amp;gt;&amp;gt; README.md
git init
git add README.md
git commit -m &amp;quot;ci: initial commit&amp;quot;
git branch -M main
git remote add origin git@github.com:&amp;lt;YOUR_USERNAME&amp;gt;/template-express-typescript-blueprint.git
git push -u origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Engine Locking&lt;/h3&gt;
&lt;p&gt;The same Node engine and package management that we use should be available to all developers working on this project. We create two new files in order to achieve that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.nvmrc&lt;/code&gt;: Will disclose to other project users the Node version that is being utilized.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.npmrc&lt;/code&gt;: reveals to other project users the package manager being used.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;.nvmrc&lt;/code&gt; is a file that is used to specify the Node version that is being used.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .nvmrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.nvmrc&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;lts/fermium
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.npmrc&lt;/code&gt; is a file that is used to specify the package manager that is being used.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .npmrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.npmrc&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;engine-strict=true
save-exact = true
tag-version-prefix=&amp;quot;&amp;quot;
strict-peer-dependencies = false
auto-install-peers = true
lockfile = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we&amp;#39;ll add few things to our &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;template-express-typescript-blueprint&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;0.0.0&amp;quot;,
  &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,
  &amp;quot;keywords&amp;quot;: [],
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;author&amp;quot;: {
    &amp;quot;name&amp;quot;: &amp;quot;Mohammad Abu Mattar&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;mohammad.abumattar@outlook.com&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;https://mkabumattar.github.io/&amp;quot;
  },
  &amp;quot;homepage&amp;quot;: &amp;quot;https://github.com/MKAbuMattar/template-express-typescript-blueprint#readme&amp;quot;,
  &amp;quot;repository&amp;quot;: {
    &amp;quot;type&amp;quot;: &amp;quot;git&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;git+https://github.com/MKAbuMattar/template-express-typescript-blueprint.git&amp;quot;
  },
  &amp;quot;bugs&amp;quot;: {
    &amp;quot;url&amp;quot;: &amp;quot;https://github.com/MKAbuMattar/template-express-typescript-blueprint/issues&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notably, the usage of &lt;code&gt;engine-strict&lt;/code&gt; said nothing about yarn in particular; we handle that in &lt;code&gt;packages.json&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;open &lt;code&gt;packages.json&lt;/code&gt; add the engines:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  ...,
   &amp;quot;engines&amp;quot;: {
    &amp;quot;node&amp;quot;: &amp;quot;&amp;gt;=14.0.0&amp;quot;,
    &amp;quot;yarn&amp;quot;: &amp;quot;&amp;gt;=1.20.0&amp;quot;,
    &amp;quot;npm&amp;quot;: &amp;quot;please-use-yarn&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Installing and Configuring TypeScript&lt;/h3&gt;
&lt;p&gt;TypeScript is available as a package in the yarn registry. We can install it with the following command to install it as a dev dependency:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add -D typescript @types/node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that TypeScript is installed in your project, we can initialize the configuration file with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn tsc --init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can start config the typescript configuration file.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;compilerOptions&amp;quot;: {
    &amp;quot;target&amp;quot;: &amp;quot;es2016&amp;quot;,
    &amp;quot;module&amp;quot;: &amp;quot;commonjs&amp;quot;,
    &amp;quot;rootDir&amp;quot;: &amp;quot;./src&amp;quot;,
    &amp;quot;moduleResolution&amp;quot;: &amp;quot;node&amp;quot;,
    &amp;quot;baseUrl&amp;quot;: &amp;quot;./src&amp;quot;,
    &amp;quot;declaration&amp;quot;: true,
    &amp;quot;emitDeclarationOnly&amp;quot;: true,
    &amp;quot;outDir&amp;quot;: &amp;quot;./build&amp;quot;,
    &amp;quot;esModuleInterop&amp;quot;: true,
    &amp;quot;forceConsistentCasingInFileNames&amp;quot;: true,
    &amp;quot;strict&amp;quot;: true,
    &amp;quot;skipLibCheck&amp;quot;: true
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Installing and Configuring Babel&lt;/h3&gt;
&lt;p&gt;In order to set up babel in the project, we must first install three main packages.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;babel-core&lt;/code&gt;: The primary package for running any babel setup or configuration is babel-core.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;babel-node&lt;/code&gt;: Any version of ES may be converted to ordinary JavaScript using the babel-node library.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;babel-preset-env&lt;/code&gt;: This package gives us access to forthcoming functionalities that &lt;code&gt;node.js&lt;/code&gt; does not yet comprehend. New features are constantly being developed, thus it will probably take some time for NodeJS to incorporate them.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add -D @babel/cli @babel/core @babel/node @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime @babel/preset-env @babel/preset-typescript @babel/runtime babel-core babel-plugin-module-resolver babel-plugin-source-map-support
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, we need to create a file called &lt;code&gt;.babelrc&lt;/code&gt; in the project’s root directory, and we paste the following block of code there.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .babelrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.babelrc&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;presets&amp;quot;: [&amp;quot;@babel/preset-env&amp;quot;, &amp;quot;@babel/preset-typescript&amp;quot;],
  &amp;quot;plugins&amp;quot;: [
    &amp;quot;@babel/plugin-proposal-class-properties&amp;quot;,
    &amp;quot;@babel/plugin-transform-runtime&amp;quot;,
    &amp;quot;source-map-support&amp;quot;
  ],
  &amp;quot;sourceMaps&amp;quot;: &amp;quot;inline&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following line to the &lt;code&gt;package.json&lt;/code&gt; file to compile, and build the code with babel:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;build:compile&amp;quot;: &amp;quot;npx babel src --extensions .ts --out-dir build --source-maps&amp;quot;,
    &amp;quot;build:types&amp;quot;: &amp;quot;tsc&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to add &lt;code&gt;.gitignore&lt;/code&gt; file to the project, and add the following line to it:&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;.gitignore&lt;/code&gt; file tells Git which files to ignore when committing your project to the GitHub repository. gitignore is located in the root directory of your repo.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch .gitignore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of &amp;#39;npm pack&amp;#39;
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp
.cache

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Code Formatting and Quality Tools&lt;/h3&gt;
&lt;p&gt;We will be using two tools in order to establish a standard that will be utilized by all project participants to maintain consistency in the coding style and the use of fundamental best practices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/&quot; target=&quot;__blank&quot;&gt;
  Prettier
&lt;/a&gt;
: A tool that will help us to format our code consistently.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/&quot; target=&quot;__blank&quot;&gt;
  ESLint
&lt;/a&gt;
: A tool that will help us to enforce a consistent coding style.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Installing and Configuring Prettier&lt;/h4&gt;
&lt;p&gt;Prettier will handle the automated file formatting for us. Add it to the project right now.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add -D prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, I advise getting the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode&quot; target=&quot;__blank&quot;&gt;Prettier VS Code extension&lt;/a&gt; so that you may avoid using the command line tool and have VS Code take care of the file formatting for you. It’s still required to include it here even when it’s installed and set up in your project since VSCode will utilize your project’s settings.&lt;/p&gt;
&lt;p&gt;We’ll create two files in the root:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.prettierrc&lt;/code&gt;: This file will contain the configuration for prettier.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.prettierignore&lt;/code&gt;: This file will contain the list of files that should be ignored by prettier.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;.prettierrc&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;trailingComma&amp;quot;: &amp;quot;all&amp;quot;,
  &amp;quot;printWidth&amp;quot;: 80,
  &amp;quot;tabWidth&amp;quot;: 2,
  &amp;quot;useTabs&amp;quot;: false,
  &amp;quot;semi&amp;quot;: false,
  &amp;quot;singleQuote&amp;quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.prettierignore&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;node_modules
build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve listed the folders in that file that I don’t want Prettier to waste any time working on. If you’d want to disregard specific file types in groups, you may also use patterns like *.html.&lt;/p&gt;
&lt;p&gt;Now we add a new script to &lt;code&gt;package.json&lt;/code&gt; so we can run Prettier:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;scripts: {
  ...,
  &amp;quot;prettier&amp;quot;: &amp;quot;prettier --write \&amp;quot;src/**/*.ts\&amp;quot;&amp;quot;,
  &amp;quot;prettier:check&amp;quot;: &amp;quot;prettier --check \&amp;quot;src/**/*.ts\&amp;quot;&amp;quot;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now run &lt;code&gt;yarn prettier&lt;/code&gt; to format all files in the project, or &lt;code&gt;yarn prettier:check&lt;/code&gt; to check if all files are formatted correctly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn prettier:check
yarn prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to automatically format, repair, and save all files in your project that you haven’t ignored. My formatter updated around 7 files by default. The source control tab on the left of VS Code has a list of altered files where you may find them.&lt;/p&gt;
&lt;h4&gt;Installing and Configuring ESLint&lt;/h4&gt;
&lt;p&gt;We’ll begin with ESLint, which is a tool that will help us to enforce a consistent coding style, at first need to install the dependencies.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-config-standard eslint-plugin-import eslint-plugin-node eslint-plugin-prettier eslint-plugin-promise
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’ll create two files in the root:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.eslintrc&lt;/code&gt;: This file will contain the configuration for ESLint.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.eslintignore&lt;/code&gt;: This file will contain the list of files that should be ignored by ESLint.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;.eslintrc&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;parser&amp;quot;: &amp;quot;@typescript-eslint/parser&amp;quot;,
  &amp;quot;parserOptions&amp;quot;: {
    &amp;quot;ecmaVersion&amp;quot;: 12,
    &amp;quot;sourceType&amp;quot;: &amp;quot;module&amp;quot;
  },
  &amp;quot;plugins&amp;quot;: [&amp;quot;@typescript-eslint&amp;quot;],
  &amp;quot;extends&amp;quot;: [&amp;quot;eslint:recommended&amp;quot;, &amp;quot;plugin:@typescript-eslint/recommended&amp;quot;],
  &amp;quot;rules&amp;quot;: {
    &amp;quot;@typescript-eslint/no-unused-vars&amp;quot;: &amp;quot;error&amp;quot;,
    &amp;quot;@typescript-eslint/consistent-type-definitions&amp;quot;: [&amp;quot;error&amp;quot;, &amp;quot;interface&amp;quot;]
  },
  &amp;quot;env&amp;quot;: {
    &amp;quot;browser&amp;quot;: true,
    &amp;quot;es2021&amp;quot;: true
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.eslintignore&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;node_modules
build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we add a new script to &lt;code&gt;package.json&lt;/code&gt; so we can run ESLint:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;scripts: {
  ...,
  &amp;quot;lint&amp;quot;: &amp;quot;eslint --ignore-path .eslintignore \&amp;quot;src/**/*.ts\&amp;quot; --fix&amp;quot;,
  &amp;quot;lint:check&amp;quot;: &amp;quot;eslint --ignore-path .eslintignore \&amp;quot;src/**/*.ts\&amp;quot;&amp;quot;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can test out your config by running:&lt;/p&gt;
&lt;p&gt;You can now run &lt;code&gt;yarn lint&lt;/code&gt; to format all files in the project, or &lt;code&gt;yarn lint:check&lt;/code&gt; to check if all files are formatted correctly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn lint:check
yarn lint
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Git Hooks&lt;/h3&gt;
&lt;p&gt;Before moving on to component development, there is one more section on configuration. If you want to expand on this project in the future, especially with a team of other developers, keep in mind that you’ll want it to be as stable as possible. To get it right from the beginning is time well spent.&lt;/p&gt;
&lt;p&gt;We’re going to use a program called &lt;a href=&quot;https://husky.run/&quot; target=&quot;__blank&quot;&gt;Husky&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Installing and Configuring Husky&lt;/h4&gt;
&lt;p&gt;Husky is a tool for executing scripts at various git stages, such as add, commit, push, etc. We would like to be able to specify requirements and, provided our project is of acceptable quality, only enable actions like commit and push to proceed if our code satisfies those requirements.&lt;/p&gt;
&lt;p&gt;To install Husky run&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add husky

yarn husky install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;.husky&lt;/code&gt; directory will be created in your project by the second command. Your hooks will be located here. As it is meant for other developers as well as yourself, make sure this directory is included in your code repository.&lt;/p&gt;
&lt;p&gt;Add the following script to your &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;scripts: {
  ...,
  &amp;quot;prepare&amp;quot;: &amp;quot;husky install&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will ensure Husky gets installed automatically when other developers run the project.&lt;/p&gt;
&lt;p&gt;To create a hook run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;npx husky add .husky/pre-commit &amp;quot;yarn lint&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The aforementioned states that the &lt;code&gt;yarn lint&lt;/code&gt; script must run and be successful before our commit may be successful. Success here refers to the absence of mistakes. You will be able to get warnings (remember in the ESLint config a setting of 1 is a warning and 2 is an error in case you want to adjust settings).&lt;/p&gt;
&lt;p&gt;We’re going to add another one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;npx husky add .husky/pre-push &amp;quot;yarn build&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes sure that we can’t push to the remote repository until our code has built correctly. That sounds like a very acceptable requirement, don’t you think? By making this adjustment and attempting to push, feel free to test it.&lt;/p&gt;
&lt;h4&gt;Installing and Configuring Commitlint&lt;/h4&gt;
&lt;p&gt;Finally, we’ll add one more tool. Let’s make sure that everyone on the team is adhering to them as well (including ourselves! ), since we have been using a uniform format for all of our commit messages so far. For our commit messages, we may add a linter.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add -D @commitlint/config-conventional @commitlint/cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will configure it using a set of common defaults, but since I occasionally forget what prefixes are available, I like to explicitly provide that list in a &lt;code&gt;commitlint.config.js&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch commitlint.config.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;commitlint.config.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
// ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
// docs: Documentation only changes
// feat: A new feature
// fix: A bug fix
// perf: A code change that improves performance
// refactor: A code change that neither fixes a bug nor adds a feature
// style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
// test: Adding missing tests or correcting existing tests
module.exports = {
  extends: [&amp;#39;@commitlint/config-conventional&amp;#39;],
  rules: {
    &amp;#39;body-leading-blank&amp;#39;: [1, &amp;#39;always&amp;#39;],
    &amp;#39;body-max-line-length&amp;#39;: [2, &amp;#39;always&amp;#39;, 100],
    &amp;#39;footer-leading-blank&amp;#39;: [1, &amp;#39;always&amp;#39;],
    &amp;#39;footer-max-line-length&amp;#39;: [2, &amp;#39;always&amp;#39;, 100],
    &amp;#39;header-max-length&amp;#39;: [2, &amp;#39;always&amp;#39;, 100],
    &amp;#39;scope-case&amp;#39;: [2, &amp;#39;always&amp;#39;, &amp;#39;lower-case&amp;#39;],
    &amp;#39;subject-case&amp;#39;: [
      2,
      &amp;#39;never&amp;#39;,
      [&amp;#39;sentence-case&amp;#39;, &amp;#39;start-case&amp;#39;, &amp;#39;pascal-case&amp;#39;, &amp;#39;upper-case&amp;#39;],
    ],
    &amp;#39;subject-empty&amp;#39;: [2, &amp;#39;never&amp;#39;],
    &amp;#39;subject-full-stop&amp;#39;: [2, &amp;#39;never&amp;#39;, &amp;#39;.&amp;#39;],
    &amp;#39;type-case&amp;#39;: [2, &amp;#39;always&amp;#39;, &amp;#39;lower-case&amp;#39;],
    &amp;#39;type-empty&amp;#39;: [2, &amp;#39;never&amp;#39;],
    &amp;#39;type-enum&amp;#39;: [
      2,
      &amp;#39;always&amp;#39;,
      [
        &amp;#39;build&amp;#39;,
        &amp;#39;chore&amp;#39;,
        &amp;#39;ci&amp;#39;,
        &amp;#39;docs&amp;#39;,
        &amp;#39;feat&amp;#39;,
        &amp;#39;fix&amp;#39;,
        &amp;#39;perf&amp;#39;,
        &amp;#39;refactor&amp;#39;,
        &amp;#39;revert&amp;#39;,
        &amp;#39;style&amp;#39;,
        &amp;#39;test&amp;#39;,
        &amp;#39;translation&amp;#39;,
        &amp;#39;security&amp;#39;,
        &amp;#39;changeset&amp;#39;,
      ],
    ],
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Afterward, use Husky to enable commitlint by using:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;npx husky add .husky/commit-msg &amp;#39;npx --no -- commitlint --edit &amp;quot;$1&amp;quot;&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;now push your changes to the remote repository and you’ll be able to commit with a valid commit message.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git add .
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git commit -m &amp;quot;ci: eslint | prettier | husky&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;╭─mkabumattar@mkabumattar in repo: template-express-typescript-blueprint on  main [+] is  v0.0.0 via  v18.4.0 took 41ms
╰─λ git commit -m &amp;quot;ci: eslint | prettier | husky&amp;quot;
yarn run v1.22.18
$ eslint --ignore-path .eslintignore &amp;quot;src/**/*.ts&amp;quot; --fix
Done in 1.31s.
[main 7fbc14f] ci: eslint | prettier | husky
17 files changed, 4484 insertions(+)
create mode 100644 .babelrc
create mode 100644 .eslintignore
create mode 100644 .eslintrc
create mode 100644 .gitattributes
create mode 100644 .gitignore
create mode 100755 .husky/commit-msg
create mode 100755 .husky/pre-commit
create mode 100755 .husky/pre-push
create mode 100644 .npmrc
create mode 100644 .nvmrc
create mode 100644 .prettierignore
create mode 100644 .prettierrc
create mode 100644 commitlint.config.js
create mode 100644 package.json
create mode 100644 src/index.ts
create mode 100644 tsconfig.json
create mode 100644 yarn.lock
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git push -u origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;╭─mkabumattar@mkabumattar in repo: template-express-typescript-blueprint on  main [⇡1] is v0.0.0 via  v18.4.0 took 2s
╰─λ git push -u origin main
yarn run v1.22.18
$ yarn build:compile &amp;amp;&amp;amp; yarn build:types
$ npx babel src --extensions .ts --out-dir build --source-maps
Successfully compiled 1 file with Babel (360ms).
$ tsc
Done in 2.63s.
Enumerating objects: 21, done.
Counting objects: 100% (21/21), done.
Delta compression using up to 4 threads
Compressing objects: 100% (16/16), done.
Writing objects: 100% (20/20), 79.42 KiB | 9.93 MiB/s, done.
Total 20 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), done.
To github.com:MKAbuMattar/template-express-typescript-blueprint.git
1583ab9..7fbc14f  main -&amp;gt; main
branch &amp;#39;main&amp;#39; set up to track &amp;#39;origin/main&amp;#39;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create somple setup express, typescript and babel application&lt;/h2&gt;
&lt;p&gt;Create a file structure like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;├── src
│   ├── index.ts
│   └── bin
│       └── www.ts
├────── constants
│       └── api.constant.ts
│       └── http.code.constant.ts
│       └── http.reason.constant.ts
│       └── message.constant.ts
├────── interfaces
│       └── controller.interface.ts
├────── middlewares
│       └── error.middleware.ts
├────── utils
│       └── logger.util.ts
│       └── exceptions
│           └── http.exception.ts
├── .babelrc
├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .gitignore
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── commitlint.config.js
├── package.json
├── README.md
├── tsconfig.json
├── yarn.lock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;start to add express and typescript dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add express
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add -D @types/express
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;New we’ll add a new package:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;compression&lt;/code&gt;: Your &lt;code&gt;Node.js&lt;/code&gt; app’s main file contains middleware for &lt;code&gt;compression&lt;/code&gt;. GZIP, which supports a variety of &lt;code&gt;compression&lt;/code&gt; techniques, will then be enabled. Your JSON response and any static file replies will be smaller as a result.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add compression
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cookie-parser&lt;/code&gt;: Your &lt;code&gt;Node.js&lt;/code&gt; app’s main file contains middleware for &lt;code&gt;cookie-parser&lt;/code&gt;. This middleware will parse the cookies in the request and set them as properties of the request object.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add cookie-parser
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;core-js&lt;/code&gt;: Your &lt;code&gt;Node.js&lt;/code&gt; app’s main file contains middleware for &lt;code&gt;core-js&lt;/code&gt;. This middleware will add the necessary polyfills to your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add core-js
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cors&lt;/code&gt;: Your &lt;code&gt;Node.js&lt;/code&gt; app’s main file contains middleware for &lt;code&gt;cors&lt;/code&gt;. This middleware will add the necessary headers to your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add cors
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;helmet&lt;/code&gt;: Your &lt;code&gt;Node.js&lt;/code&gt; app’s main file contains middleware for &lt;code&gt;helmet&lt;/code&gt;. This middleware will add security headers to your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add helmet
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;regenerator-runtime&lt;/code&gt;: Your &lt;code&gt;Node.js&lt;/code&gt; app’s main file contains middleware for &lt;code&gt;regenerator-runtime&lt;/code&gt;. This middleware will add the necessary polyfills to your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add regenerator-runtime
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;after that we need to add the type for the dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add -D @types/compression @types/cookie-parser @types/core-js @types/cors @types/regenerator-runtime
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;now we&amp;#39;ll start with create constants and we&amp;#39;ll add new things after that:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;api.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class Api {
  public static readonly ROOT: string = &amp;#39;/&amp;#39;;

  public static readonly API: string = &amp;#39;/api&amp;#39;;
}
export default Api;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;http.code.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class HttpCode {
  public static readonly CONTINUE: number = 100;

  public static readonly SWITCHING_PROTOCOLS: number = 101;

  public static readonly PROCESSING: number = 102;

  public static readonly OK: number = 200;

  public static readonly CREATED: number = 201;

  public static readonly ACCEPTED: number = 202;

  public static readonly NON_AUTHORITATIVE_INFORMATION: number = 203;

  public static readonly NO_CONTENT: number = 204;

  public static readonly RESET_CONTENT: number = 205;

  public static readonly PARTIAL_CONTENT: number = 206;

  public static readonly MULTI_STATUS: number = 207;

  public static readonly ALREADY_REPORTED: number = 208;

  public static readonly IM_USED: number = 226;

  public static readonly MULTIPLE_CHOICES: number = 300;

  public static readonly MOVED_PERMANENTLY: number = 301;

  public static readonly MOVED_TEMPORARILY: number = 302;

  public static readonly SEE_OTHER: number = 303;

  public static readonly NOT_MODIFIED: number = 304;

  public static readonly USE_PROXY: number = 305;

  public static readonly SWITCH_PROXY: number = 306;

  public static readonly TEMPORARY_REDIRECT: number = 307;

  public static readonly BAD_REQUEST: number = 400;

  public static readonly UNAUTHORIZED: number = 401;

  public static readonly PAYMENT_REQUIRED: number = 402;

  public static readonly FORBIDDEN: number = 403;

  public static readonly NOT_FOUND: number = 404;

  public static readonly METHOD_NOT_ALLOWED: number = 405;

  public static readonly NOT_ACCEPTABLE: number = 406;

  public static readonly PROXY_AUTHENTICATION_REQUIRED: number = 407;

  public static readonly REQUEST_TIMEOUT: number = 408;

  public static readonly CONFLICT: number = 409;

  public static readonly GONE: number = 410;

  public static readonly LENGTH_REQUIRED: number = 411;

  public static readonly PRECONDITION_FAILED: number = 412;

  public static readonly PAYLOAD_TOO_LARGE: number = 413;

  public static readonly REQUEST_URI_TOO_LONG: number = 414;

  public static readonly UNSUPPORTED_MEDIA_TYPE: number = 415;

  public static readonly REQUESTED_RANGE_NOT_SATISFIABLE: number = 416;

  public static readonly EXPECTATION_FAILED: number = 417;

  public static readonly IM_A_TEAPOT: number = 418;

  public static readonly METHOD_FAILURE: number = 420;

  public static readonly MISDIRECTED_REQUEST: number = 421;

  public static readonly UNPROCESSABLE_ENTITY: number = 422;

  public static readonly LOCKED: number = 423;

  public static readonly FAILED_DEPENDENCY: number = 424;

  public static readonly UPGRADE_REQUIRED: number = 426;

  public static readonly PRECONDITION_REQUIRED: number = 428;

  public static readonly TOO_MANY_REQUESTS: number = 429;

  public static readonly REQUEST_HEADER_FIELDS_TOO_LARGE: number = 431;

  public static readonly UNAVAILABLE_FOR_LEGAL_REASONS: number = 451;

  public static readonly INTERNAL_SERVER_ERROR: number = 500;

  public static readonly NOT_IMPLEMENTED: number = 501;

  public static readonly BAD_GATEWAY: number = 502;

  public static readonly SERVICE_UNAVAILABLE: number = 503;

  public static readonly GATEWAY_TIMEOUT: number = 504;

  public static readonly HTTP_VERSION_NOT_SUPPORTED: number = 505;

  public static readonly VARIANT_ALSO_NEGOTIATES: number = 506;

  public static readonly INSUFFICIENT_STORAGE: number = 507;

  public static readonly LOOP_DETECTED: number = 508;

  public static readonly NOT_EXTENDED: number = 510;

  public static readonly NETWORK_AUTHENTICATION_REQUIRED: number = 511;

  public static readonly NETWORK_CONNECT_TIMEOUT_ERROR: number = 599;
}

export default HttpCode;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;http.reason.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class HttpReason {
  public static readonly CONTINUE: string = &amp;#39;Continue&amp;#39;;

  public static readonly SWITCHING_PROTOCOLS: string = &amp;#39;Switching Protocols&amp;#39;;

  public static readonly PROCESSING: string = &amp;#39;Processing&amp;#39;;

  public static readonly OK: string = &amp;#39;OK&amp;#39;;

  public static readonly CREATED: string = &amp;#39;Created&amp;#39;;

  public static readonly ACCEPTED: string = &amp;#39;Accepted&amp;#39;;

  public static readonly NON_AUTHORITATIVE_INFORMATION: string =
    &amp;#39;Non-Authoritative Information&amp;#39;;

  public static readonly NO_CONTENT: string = &amp;#39;No Content&amp;#39;;

  public static readonly RESET_CONTENT: string = &amp;#39;Reset Content&amp;#39;;

  public static readonly PARTIAL_CONTENT: string = &amp;#39;Partial Content&amp;#39;;

  public static readonly MULTI_STATUS: string = &amp;#39;Multi-Status&amp;#39;;

  public static readonly ALREADY_REPORTED: string = &amp;#39;Already Reported&amp;#39;;

  public static readonly IM_USED: string = &amp;#39;IM Used&amp;#39;;

  public static readonly MULTIPLE_CHOICES: string = &amp;#39;Multiple Choices&amp;#39;;

  public static readonly MOVED_PERMANENTLY: string = &amp;#39;Moved Permanently&amp;#39;;

  public static readonly MOVED_TEMPORARILY: string = &amp;#39;Moved Temporarily&amp;#39;;

  public static readonly SEE_OTHER: string = &amp;#39;See Other&amp;#39;;

  public static readonly NOT_MODIFIED: string = &amp;#39;Not Modified&amp;#39;;

  public static readonly USE_PROXY: string = &amp;#39;Use Proxy&amp;#39;;

  public static readonly SWITCH_PROXY: string = &amp;#39;Switch Proxy&amp;#39;;

  public static readonly TEMPORARY_REDIRECT: string = &amp;#39;Temporary Redirect&amp;#39;;

  public static readonly BAD_REQUEST: string = &amp;#39;Bad Request&amp;#39;;

  public static readonly UNAUTHORIZED: string = &amp;#39;Unauthorized&amp;#39;;

  public static readonly PAYMENT_REQUIRED: string = &amp;#39;Payment Required&amp;#39;;

  public static readonly FORBIDDEN: string = &amp;#39;Forbidden&amp;#39;;

  public static readonly NOT_FOUND: string = &amp;#39;Not Found&amp;#39;;

  public static readonly METHOD_NOT_ALLOWED: string = &amp;#39;Method Not Allowed&amp;#39;;

  public static readonly NOT_ACCEPTABLE: string = &amp;#39;Not Acceptable&amp;#39;;

  public static readonly PROXY_AUTHENTICATION_REQUIRED: string =
    &amp;#39;Proxy Authentication Required&amp;#39;;

  public static readonly REQUEST_TIMEOUT: string = &amp;#39;Request Timeout&amp;#39;;

  public static readonly CONFLICT: string = &amp;#39;Conflict&amp;#39;;

  public static readonly GONE: string = &amp;#39;Gone&amp;#39;;

  public static readonly LENGTH_REQUIRED: string = &amp;#39;Length Required&amp;#39;;

  public static readonly PRECONDITION_FAILED: string = &amp;#39;Precondition Failed&amp;#39;;

  public static readonly PAYLOAD_TOO_LARGE: string = &amp;#39;Payload Too Large&amp;#39;;

  public static readonly REQUEST_URI_TOO_LONG: string = &amp;#39;Request URI Too Long&amp;#39;;

  public static readonly UNSUPPORTED_MEDIA_TYPE: string =
    &amp;#39;Unsupported Media Type&amp;#39;;

  public static readonly REQUESTED_RANGE_NOT_SATISFIABLE: string =
    &amp;#39;Requested Range Not Satisfiable&amp;#39;;

  public static readonly EXPECTATION_FAILED: string = &amp;#39;Expectation Failed&amp;#39;;

  public static readonly IM_A_TEAPOT: string = &amp;quot;I&amp;#39;m a teapot&amp;quot;;

  public static readonly METHOD_FAILURE: string = &amp;#39;Method Failure&amp;#39;;

  public static readonly MISDIRECTED_REQUEST: string = &amp;#39;Misdirected Request&amp;#39;;

  public static readonly UNPROCESSABLE_ENTITY: string = &amp;#39;Unprocessable Entity&amp;#39;;

  public static readonly LOCKED: string = &amp;#39;Locked&amp;#39;;

  public static readonly FAILED_DEPENDENCY: string = &amp;#39;Failed Dependency&amp;#39;;

  public static readonly UPGRADE_REQUIRED: string = &amp;#39;Upgrade Required&amp;#39;;

  public static readonly PRECONDITION_REQUIRED: string =
    &amp;#39;Precondition Required&amp;#39;;

  public static readonly TOO_MANY_REQUESTS: string = &amp;#39;Too Many Requests&amp;#39;;

  public static readonly REQUEST_HEADER_FIELDS_TOO_LARGE: string =
    &amp;#39;Request Header Fields Too Large&amp;#39;;

  public static readonly UNAVAILABLE_FOR_LEGAL_REASONS: string =
    &amp;#39;Unavailable For Legal Reasons&amp;#39;;

  public static readonly INTERNAL_SERVER_ERROR: string =
    &amp;#39;Internal Server Error&amp;#39;;

  public static readonly NOT_IMPLEMENTED: string = &amp;#39;Not Implemented&amp;#39;;

  public static readonly BAD_GATEWAY: string = &amp;#39;Bad Gateway&amp;#39;;

  public static readonly SERVICE_UNAVAILABLE: string = &amp;#39;Service Unavailable&amp;#39;;

  public static readonly GATEWAY_TIMEOUT: string = &amp;#39;Gateway Timeout&amp;#39;;

  public static readonly HTTP_VERSION_NOT_SUPPORTED: string =
    &amp;#39;HTTP Version Not Supported&amp;#39;;

  public static readonly VARIANT_ALSO_NEGOTIATES: string =
    &amp;#39;Variant Also Negotiates&amp;#39;;

  public static readonly INSUFFICIENT_STORAGE: string = &amp;#39;Insufficient Storage&amp;#39;;

  public static readonly LOOP_DETECTED: string = &amp;#39;Loop Detected&amp;#39;;

  public static readonly NOT_EXTENDED: string = &amp;#39;Not Extended&amp;#39;;

  public static readonly NETWORK_AUTHENTICATION_REQUIRED: string =
    &amp;#39;Network Authentication Required&amp;#39;;

  public static readonly NETWORK_CONNECT_TIMEOUT_ERROR: string =
    &amp;#39;Network Connect Timeout Error&amp;#39;;
}

export default HttpReason;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;message.constant.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class Message {
  public static readonly API_WORKING: string = &amp;#39;API is working&amp;#39;;

  public static readonly SOMETHING_WENT_WRONG: string = &amp;#39;Something went wrong&amp;#39;;
}
export default Message;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;utils/exception/http.exception.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class HttpException extends Error {
  public statusCode: number;

  public statusMsg: string;

  public msg: string;

  constructor(statusCode: number, statusMsg: string, msg: any) {
    super(msg);
    this.statusCode = statusCode;
    this.statusMsg = statusMsg;
    this.msg = msg;
  }
}

export default HttpException;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;error.middleware.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// http constant
import ConstantHttpCode from &amp;#39;@/constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;@/constants/http.reason.constant&amp;#39;;
// message constant
import ConstantMessage from &amp;#39;@/constants/message.constant&amp;#39;;
import HttpException from &amp;#39;@/utils/exceptions/http.exception&amp;#39;;
import {Request, Response, NextFunction} from &amp;#39;express&amp;#39;;

const errorMiddleware = (
  error: HttpException,
  _req: Request,
  res: Response,
  next: NextFunction,
): Response | void =&amp;gt; {
  try {
    const statusCode =
      error.statusCode || ConstantHttpCode.INTERNAL_SERVER_ERROR;
    const statusMsg =
      error.statusMsg || ConstantHttpReason.INTERNAL_SERVER_ERROR;
    const msg = error.msg || ConstantMessage.SOMETHING_WENT_WRONG;

    return res.status(statusCode).send({
      status: {
        code: statusCode,
        msg: statusMsg,
      },
      msg: msg,
    });
  } catch (err) {
    return next(err);
  }
};

export default errorMiddleware;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;controller.interface.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import {Router} from &amp;#39;express&amp;#39;;

interface Controller {
  path: string;
  router: Router;
}

export default Controller;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;index.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// api constant
import ConstantAPI from &amp;#39;./constants/api.constant&amp;#39;;
// http constant
import ConstantHttpCode from &amp;#39;./constants/http.code.constant&amp;#39;;
import ConstantHttpReason from &amp;#39;./constants/http.reason.constant&amp;#39;;
// message constant
import ConstantMessage from &amp;#39;./constants/message.constant&amp;#39;;
import Controller from &amp;#39;./interfaces/controller.interface&amp;#39;;
import ErrorMiddleware from &amp;#39;./middlewares/error.middleware&amp;#39;;
import HttpException from &amp;#39;./utils/exceptions/http.exception&amp;#39;;
import compression from &amp;#39;compression&amp;#39;;
import cookieParser from &amp;#39;cookie-parser&amp;#39;;
import cors from &amp;#39;cors&amp;#39;;
import express, {Application, Request, Response, NextFunction} from &amp;#39;express&amp;#39;;
import helmet from &amp;#39;helmet&amp;#39;;

class App {
  public app: Application;

  constructor(controllers: Controller[]) {
    this.app = express();

    this.initialiseConfig();
    this.initialiseRoutes();
    this.initialiseControllers(controllers);
    this.initialiseErrorHandling();
  }

  private initialiseConfig(): void {
    this.app.use(express.json());
    this.app.use(express.urlencoded({extended: true}));
    this.app.use(cookieParser());
    this.app.use(compression());
    this.app.use(cors());
    this.app.use(helmet());
  }

  private initialiseRoutes(): void {
    this.app.get(
      ConstantAPI.ROOT,
      (_req: Request, res: Response, next: NextFunction) =&amp;gt; {
        try {
          return res.status(ConstantHttpCode.OK).json({
            status: {
              code: ConstantHttpCode.OK,
              msg: ConstantHttpReason.OK,
            },
            msg: ConstantMessage.API_WORKING,
          });
        } catch (err: any) {
          return next(
            new HttpException(
              ConstantHttpCode.INTERNAL_SERVER_ERROR,
              ConstantHttpReason.INTERNAL_SERVER_ERROR,
              err.message,
            ),
          );
        }
      },
    );
  }

  private initialiseControllers(controllers: Controller[]): void {
    controllers.forEach((controller: Controller) =&amp;gt; {
      this.app.use(ConstantAPI.API, controller.router);
    });
  }

  private initialiseErrorHandling(): void {
    this.app.use(ErrorMiddleware);
  }
}

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;www.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;#!/usr/bin/env ts-node
import App from &amp;#39;..&amp;#39;;
import &amp;#39;core-js/stable&amp;#39;;
import http from &amp;#39;http&amp;#39;;
import &amp;#39;regenerator-runtime/runtime&amp;#39;;

// controllers

const {app} = new App([]);

/**
 * Normalize a port into a number, string, or false.
 */
const normalizePort = (val: any) =&amp;gt; {
  const port = parseInt(val, 10);

  if (Number.isNaN(port)) {
    // named pipe
    return val;
  }

  if (port &amp;gt;= 0) {
    // port number
    return port;
  }

  return false;
};

const port = normalizePort(&amp;#39;3030&amp;#39;);
app.set(&amp;#39;port&amp;#39;, port);

/**
 * Create HTTP server.
 */
const server = http.createServer(app);

/**
 * Event listener for HTTP server &amp;quot;error&amp;quot; event.
 */
const onError = (error: any) =&amp;gt; {
  if (error.syscall !== &amp;#39;listen&amp;#39;) {
    throw error;
  }

  const bind = typeof port === &amp;#39;string&amp;#39; ? `Pipe ${port}` : `Port ${port}`;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case &amp;#39;EACCES&amp;#39;:
      console.error(`${bind} requires elevated privileges`);
      process.exit(1);
      break;
    case &amp;#39;EADDRINUSE&amp;#39;:
      console.error(`${bind} is already in use`);
      process.exit(1);
      break;
    default:
      throw error;
  }
};

/**
 * Event listener for HTTP server &amp;quot;listening&amp;quot; event.
 */
const onListening = () =&amp;gt; {
  const addr = server.address();
  const bind = typeof addr === &amp;#39;string&amp;#39; ? `pipe ${addr}` : `port ${addr?.port}`;
  console.info(`Listening on ${bind}`);
};

server.listen(port);
server.on(&amp;#39;error&amp;#39;, onError);
server.on(&amp;#39;listening&amp;#39;, onListening);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To run the app, and start tarcking the server, with the changes, we need to add new dependency.&lt;/p&gt;
&lt;p&gt;Concurrently: is a tool to run multiple tasks at the same time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn add -D concurrently
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we&amp;#39;ll add the following command to scripts section of package.json:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;scripts&amp;quot;: {
  &amp;quot;start&amp;quot;: &amp;quot;node build/bin/www.js&amp;quot;,
  &amp;quot;clean&amp;quot;: &amp;quot;rm -rf build&amp;quot;,
  &amp;quot;build&amp;quot;: &amp;quot;yarn clean &amp;amp;&amp;amp; concurrently yarn:build:*&amp;quot;,
  &amp;quot;build:compile&amp;quot;: &amp;quot;npx babel src --extensions .ts --out-dir build --source-maps&amp;quot;,
  &amp;quot;build:types&amp;quot;: &amp;quot;tsc&amp;quot;,
  &amp;quot;dev&amp;quot;: &amp;quot;concurrently yarn:dev:* --kill-others \&amp;quot;nodemon --exec node build/bin/www.js\&amp;quot;&amp;quot;,
  &amp;quot;dev:compile&amp;quot;: &amp;quot;npx babel src --extensions .ts --out-dir build --source-maps --watch&amp;quot;,
  &amp;quot;dev:types&amp;quot;: &amp;quot;tsc --watch&amp;quot;,
  ...,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;New you can run the application with yarn start or yarn dev, and you can also run the application with yarn build to create a production version.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;yarn dev

yarn start

yarn build
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Finally, after compilation, we can now need to deploy the compiled version in the NodeJS production server.&lt;/p&gt;
&lt;p&gt;All code from this tutorial as a complete package is available in this &lt;a href=&quot;https://github.com/MKAbuMattar/template-express-typescript-blueprint/tree/part1&quot; target=&quot;__blank&quot;&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://expressjs.com/&quot;&gt;Express.js Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/&quot;&gt;Prettier Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://typicode.github.io/husky/&quot;&gt;Husky Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://commitlint.js.org/&quot;&gt;Commitlint Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yarnpkg.com/&quot;&gt;Yarn Package Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;NVM (Node Version Manager) GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/cli/v7/configuring-npm/npmrc&quot;&gt;&lt;code&gt;.npmrc&lt;/code&gt; Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/concurrently&quot;&gt;Concurrently (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zloirock/core-js&quot;&gt;Core-js (GitHub)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/helmet&quot;&gt;Helmet (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/compression&quot;&gt;Compression (npm package)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Backend Development</category><category>Node.js</category><category>TypeScript</category><category>Development Setup</category><category>JavaScript Tooling</category><author>Mohammad Abu Mattar</author><enclosure url="https://mkabumattar.com/assets/blog/0004-setting-up-node-js-express-prettier-eslint-and-husky-application-with-babel-and-typescript/hero.jpg" length="0" type="image/jpeg"/></item></channel></rss>