<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kosisochukwu Ugochukwu</title>
    <description>The latest articles on DEV Community by Kosisochukwu Ugochukwu (@kosisochukwu_ugochukwu_a2).</description>
    <link>https://dev.to/kosisochukwu_ugochukwu_a2</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2375405%2F71f54594-1c00-444e-8931-b541700b84af.jpg</url>
      <title>DEV Community: Kosisochukwu Ugochukwu</title>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kosisochukwu_ugochukwu_a2"/>
    <language>en</language>
    <item>
      <title>Deploy a .NET 8 App to Azure Kubernetes Service (AKS) – Tutorial Guide</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Fri, 19 Sep 2025 09:15:34 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/deploy-a-net-8-app-to-azure-kubernetes-service-aks-tutorial-guide-423c</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/deploy-a-net-8-app-to-azure-kubernetes-service-aks-tutorial-guide-423c</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;A beginner-friendly guide to deploying a .NET app to the cloud using Docker and Kubernetes.&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Deploying applications to the cloud can seem daunting, especially if you are new to containers and Kubernetes. This guide is designed for beginners and walks you step by step through building a simple .NET 8 Web API, packaging it in a Docker container, and deploying it to Azure Kubernetes Service (AKS). By the end, you will also have automated deployments via GitHub Actions, so any code push instantly updates your app in the cloud.&lt;/p&gt;

&lt;p&gt;Think of it as a hands-on way to learn modern cloud deployment, without getting lost in complex setups. By the time you finish, you will not only understand the tools but also gain confidence in deploying real-world apps to the cloud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What You will Learn&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By the end of this tutorial, you will know how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build a .NET 8 Web API&lt;/li&gt;
&lt;li&gt;Containerize your app with Docker&lt;/li&gt;
&lt;li&gt;Deploy containers to Kubernetes in the cloud&lt;/li&gt;
&lt;li&gt;Set up automated deployments with GitHub Actions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What You will be able Build :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple Weather API – Returns fake weather data (just like a real weather app)&lt;/li&gt;
&lt;li&gt;Containerized App – Runs in Docker containers&lt;/li&gt;
&lt;li&gt;Cloud Deployment – Hosted on Azure Kubernetes Service (AKS)&lt;/li&gt;
&lt;li&gt;Automatic Updates – Push code to GitHub → auto-deploys to Azure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Required Tools to Set Up Your Computer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install the following:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Studio Code&lt;/strong&gt; – &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;code.visualstudio.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;.NET 9 SDK – &lt;a href="https://dotnet.microsoft.com/en-us/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;dotnet.microsoft.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Desktop&lt;/strong&gt; – &lt;a href="https://www.docker.com/products/docker-desktop/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;docker.com/products/docker-desktop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start Docker Desktop after installing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure CLI&lt;/strong&gt; – &lt;a href="https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;docs.microsoft.com/cli/azure/install-azure-cli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;kubectl (Kubernetes CLI)&lt;/strong&gt; – &lt;a href="https://kubernetes.io/docs/tasks/tools/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;kubernetes.io/docs/tasks/tools/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub CLI&lt;/strong&gt; – &lt;a href="https://cli.github.com/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;cli.github.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Git&lt;/strong&gt; – &lt;a href="https://git-scm.com/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;git-scm.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Required Accounts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Account&lt;/strong&gt; – &lt;a href="https://github.com/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure Account&lt;/strong&gt; – &lt;a href="https://azure.microsoft.com/en-us/pricing/purchase-options/azure-account?icid=azurefreeaccount&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;azure.microsoft.com/free&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Test Your Setup&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Run these commands in your terminal (Command Prompt on Windows, Terminal on Mac/Linux) to verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet --version
docker --version
az --version
kubectl version --client
gh --version
git --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see version numbers for all tools. If anything fails, reinstall that tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1: Create the .NET Application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s start by building a simple .NET 8 Web API that we will later containerize and deploy to Azure.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1.1 Set Up Project Structure&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Create a new folder for your app:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir weather-app-demo
cd weather-app-demo
mkdir WeatherApp
cd WeatherApp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpjnbb97aq78sa6w8ymuj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpjnbb97aq78sa6w8ymuj.png" alt="Image d2W1" width="800" height="812"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1.2 Initialize a .NET Project&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Generate a minimal Web API template:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet new webapi -minimal&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3xm7dj72fi0vn4te7gu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3xm7dj72fi0vn4te7gu.png" alt="Image d2w2" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1.3 Add Dependencies&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Install the required packages:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks
dotnet add package Swashbuckle.AspNetCore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F725rt7qp3eudy6zdv427.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F725rt7qp3eudy6zdv427.png" alt="Image d2w3" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk971k3nfiqip0hwx43ng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk971k3nfiqip0hwx43ng.png" alt="Image d2w4" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HealthChecks – adds a &lt;code&gt;/health&lt;/code&gt; endpoint (important for Kubernetes).&lt;/li&gt;
&lt;li&gt;Swashbuckle – provides Swagger UI for API docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1.4 Write the Application Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Replace the contents of Program.cs with the following:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddHealthChecks();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Configure Kestrel to listen on port 8080 (required for containers)
builder.WebHost.ConfigureKestrel(options =&amp;gt;
{
    options.ListenAnyIP(8080);
});

var app = builder.Build();

// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment() || app.Environment.IsProduction())
{
    app.UseSwagger();
    app.UseSwaggerUI(c =&amp;gt; 
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "Weather API v1");
        c.RoutePrefix = "swagger";
    });
}

// Define API endpoints
app.MapGet("/", () =&amp;gt; new
{
    Message = "Welcome to the Weather App!",
    Version = "1.0.0",
    Environment = app.Environment.EnvironmentName,
    Timestamp = DateTime.UtcNow
})
.WithName("GetWelcome")
.WithTags("General");

app.MapGet("/weather", () =&amp;gt;
{
    var summaries = new[] { 
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", 
        "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 
    };

    var forecast = Enumerable.Range(1, 5).Select(index =&amp;gt; new
    {
        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
        TemperatureC = Random.Shared.Next(-20, 55),
        TemperatureF = 0,
        Summary = summaries[Random.Shared.Next(summaries.Length)]
    })
    .Select(temp =&amp;gt; new
    {
        temp.Date,
        temp.TemperatureC,
        TemperatureF = 32 + (int)(temp.TemperatureC / 0.5556),
        temp.Summary
    });

    return forecast;
})
.WithName("GetWeatherForecast")
.WithTags("Weather");

// Health check endpoint (required for Kubernetes)
app.MapHealthChecks("/health")
.WithTags("Health");

app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fppgihn916cdwmvdn23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fppgihn916cdwmvdn23.png" alt="Image d2w5" width="800" height="645"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1.5 Run and Test Locally&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Start the application:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet run&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw7kifhbgvjh4w1u5p5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw7kifhbgvjh4w1u5p5o.png" alt="Image d2w6" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now, test the endpoints in your browser:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://localhost:8080/&lt;/code&gt; → Welcome message&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz4ac35e0hlggcqcey10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz4ac35e0hlggcqcey10.png" alt="Image d2w7" width="800" height="125"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;http://localhost:8080/weather&lt;/code&gt; → Weather forecast&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdoitpe7lmzz0pieww70.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdoitpe7lmzz0pieww70.png" alt="Image d2w8" width="800" height="138"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;http://localhost:8080/swagger&lt;/code&gt; → API docs&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkvcpfv230dk10y99yql.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkvcpfv230dk10y99yql.png" alt="Image d2w9" width="800" height="853"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;http://localhost:8080/health&lt;/code&gt; → Health check endpoint&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl27x6iup9l38aegk139l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl27x6iup9l38aegk139l.png" alt="Image d2w10" width="786" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Press &lt;code&gt;Ctrl + C&lt;/code&gt; to stop the app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcuebo3mzwkxxz2lnps37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcuebo3mzwkxxz2lnps37.png" alt="Image d2w11" width="800" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, you have a working .NET API that’s container-ready. Next, we willl Dockerize the app so it can run inside a container.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2: Containerize Your Application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that the app runs locally, let’s package it into a Docker container so it can run consistently anywhere.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;2.1 Create a Dockerfile&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Inside the WeatherApp folder, create a file named Dockerfile (no extension) and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Multi-stage build for optimized image size

# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
EXPOSE 8080
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production

# Build stage
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src

# Copy project file and restore dependencies
COPY ["WeatherApp/WeatherApp.csproj", "."]
RUN dotnet restore "WeatherApp.csproj"

# Copy source code and build
COPY . .
WORKDIR /src
COPY WeatherApp/ ./WeatherApp/
WORKDIR /src/WeatherApp
RUN dotnet restore "WeatherApp.csproj"
RUN dotnet build "WeatherApp.csproj" -c $BUILD_CONFIGURATION -o /app/build

# Publish stage
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "WeatherApp.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

# Final stage
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WeatherApp.dll"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frykybywx9nbt8jfn7ms7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frykybywx9nbt8jfn7ms7.png" alt="Image dd2w12" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This uses a multi-stage build to keep the final image lightweight:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build stage compiles your app.&lt;/li&gt;
&lt;li&gt;Publish stage outputs optimized binaries.&lt;/li&gt;
&lt;li&gt;Final stage only contains what’s needed to run.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2.2 Create a .dockerignore File&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create a .dockerignore file in the root of your project to prevent unnecessary files from being copied into the Docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Build outputs
bin/
obj/
out/

# IDE files
.vs/
.vscode/
*.user
*.suo

# OS files
.DS_Store
Thumbs.db

# Git
.git/
.gitignore

# Documentation
README.md
*.md

# Docker
Dockerfile*
.dockerignore

# Logs
*.log
logs/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps your Docker image clean and small.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2.3 Build and Test the Container&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Build the Docker Image&lt;br&gt;
&lt;code&gt;docker build -t weather-app:local .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqz6eti3079ebvilsqdb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqz6eti3079ebvilsqdb7.png" alt="Image d2w11" width="800" height="425"&gt;&lt;/a&gt;&lt;br&gt;
Run the Container&lt;br&gt;
&lt;code&gt;docker run -d -p 8080:8080 --name weather-test weather-app:local&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0vt0vv0kj6buow591qj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0vt0vv0kj6buow591qj.png" alt="Image d2w13" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcv8up9ulqxozagd2mx4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcv8up9ulqxozagd2mx4x.png" alt="Image d2w14" width="800" height="96"&gt;&lt;/a&gt;&lt;br&gt;
Test the App Inside Docker&lt;br&gt;
&lt;code&gt;curl http://localhost:8080/&lt;/code&gt;&lt;br&gt;
&lt;code&gt;curl http://localhost:8080/weather&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7e4n9uq8rukejm625om.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7e4n9uq8rukejm625om.png" alt="Image d2w15" width="800" height="104"&gt;&lt;/a&gt;&lt;br&gt;
Or just visit in your browser:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://localhost:8080/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x9amy41ilb307744svv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x9amy41ilb307744svv.png" alt="Image d2w16" width="732" height="468"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://localhost:8080/weather" rel="noopener noreferrer"&gt;http://localhost:8080/weather&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1ubilwngid0fp2l9j6h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1ubilwngid0fp2l9j6h.png" alt="Image d2w17" width="716" height="1234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop &amp;amp; Remove the Container&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;docker stop weather-test&lt;/code&gt;&lt;br&gt;
&lt;code&gt;docker rm weather-test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm5mwaaehwatpjtbrnmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm5mwaaehwatpjtbrnmt.png" alt="Image d2w18" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, your app is running inside a container. Next, we’ll push the container to a registry and deploy it to Azure Kubernetes Service (AKS).&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 3: Set Up Azure Infrastructure&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that your app runs inside a container, it’s time to deploy it to the cloud. We will use Azure Kubernetes Service (AKS), along with Azure Container Registry (ACR) to store and distribute your Docker images.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3.1 Authenticate with Azure&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Log in to your Azure account:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az login&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This opens your browser for sign-in.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3.2 Select Your Subscription&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;List your available subscriptions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az account list --output table&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Set the subscription you want to use:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az account set --subscription "Your-Subscription-Name"&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3.3 Create a Resource Group&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A resource group is a logical container for all your Azure resources:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az group create --name student-demo --location eastus&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F255rj3sfordjanp4tejl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F255rj3sfordjanp4tejl.png" alt="Image d2w19" width="800" height="122"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3.4 Create a Container Registry (ACR)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We will use ACR to store our Docker images. Make sure the name is unique (append initials/year if needed):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az acr create \&lt;br&gt;
  --resource-group student-demo \&lt;br&gt;
  --name studentdemo3121acr \&lt;br&gt;
  --sku Basic&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7r3cymnwafwsgtrmylz2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7r3cymnwafwsgtrmylz2.png" alt="Image d2w20" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note if you have an error while creating RG for your container registry, use this code below to register namespace on your container registry: &lt;code&gt;az provider register --namespace Microsoft.ContainerRegistry&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3.5 Build &amp;amp; Push the Image to ACR&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Instead of building locally and pushing manually, we will let Azure build and push the image for us using az acr build.&lt;/p&gt;

&lt;p&gt;From the folder containing your Dockerfile:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az acr build \&lt;br&gt;
  --registry studentdemo3121acr \&lt;br&gt;
  --image weather-app:latest \&lt;br&gt;
  .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3ab3y7tp36774zsyajz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3ab3y7tp36774zsyajz.png" alt="Image d2w21" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4he8bv5id3bvwsvnsp2k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4he8bv5id3bvwsvnsp2k.png" alt="Image d2w22" width="800" height="672"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70ujpu5i12chj0jc6fdw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70ujpu5i12chj0jc6fdw.png" alt="Image d2w22" width="800" height="738"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexlp5msxd1s3u8mcsa5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexlp5msxd1s3u8mcsa5k.png" alt="Image d2w22" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: Below is what the code means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;registry studentdemo3121acr → Your ACR name&lt;/li&gt;
&lt;li&gt;image weather-app:latest → Tags the image inside ACR&lt;/li&gt;
&lt;li&gt;Uses the Dockerfile in the current directory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: This avoids compatibility issues since the build runs directly in Azure.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3.6 Create an AKS Cluster with ACR Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now let’s create the Kubernetes cluster where our app will run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az aks create \
  --resource-group student-demo \
  --name student-aks-cluster \
  --node-count 1 \
  --node-vm-size Standard_B2s \
  --attach-acr studentdemo2024acr \
  --enable-managed-identity \
  --generate-ssh-keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9o97k7bqx7frbcee4ct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9o97k7bqx7frbcee4ct.png" alt="Image d2w23" width="800" height="865"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsora1qvfb6fqrasixgkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsora1qvfb6fqrasixgkf.png" alt="Image d2w24" width="800" height="914"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgdx87wapsz4hj04z0ery.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgdx87wapsz4hj04z0ery.png" alt="Image d2w25" width="800" height="530"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6obhjnaz91327ibe6sj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6obhjnaz91327ibe6sj.png" alt="Image d2w26" width="800" height="529"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ko8rnpadehrpqmh3lwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ko8rnpadehrpqmh3lwd.png" alt="Image d2w27" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a managed AKS cluster&lt;/li&gt;
&lt;li&gt;Adds 1 VM node (2 vCPUs, 4 GB RAM)&lt;/li&gt;
&lt;li&gt;Integrates ACR automatically (avoids ImagePullBackOff errors)&lt;/li&gt;
&lt;li&gt;Generates SSH keys for secure access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now wait 5–10 minutes for Azure to provision everything (coffee break time ☕).&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3.7 Connect to Your AKS Cluster&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once the cluster is ready, configure kubectl to connect:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az aks get-credentials \&lt;br&gt;
  --resource-group student-demo \&lt;br&gt;
  --name student-aks-cluster&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzbfs97itakxun35qp88.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzbfs97itakxun35qp88.png" alt="Image d2w28" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Verify the connection:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get nodes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l6qhxm7dj4uip84udx3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l6qhxm7dj4uip84udx3.png" alt="Image d2w29" width="800" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see your Kubernetes node(s) listed.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3.8 Verify ACR Integration (Optional)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Check that your AKS cluster can pull images from ACR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CLIENT_ID=$(az aks show \
  --resource-group student-demo \
  --name student-aks-cluster \
  --query "identityProfile.kubeletidentity.clientId" \
  --output tsv)

echo "Kubelet Client ID: $CLIENT_ID"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuij0qw344unozi864ue6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuij0qw344unozi864ue6.png" alt="Image d2w30" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now confirm the role assignment:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az role assignment list \&lt;br&gt;
  --assignee $CLIENT_ID \&lt;br&gt;
  --scope $(az acr show --name studentdemo3121acr --query id --output tsv) \&lt;br&gt;
  --output table&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphd16mac3zx0fqimn07d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphd16mac3zx0fqimn07d.png" alt="Image d2w31" width="800" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see an AcrPull role. If not, create it manually:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az role assignment create \&lt;br&gt;
  --assignee $CLIENT_ID \&lt;br&gt;
  --role AcrPull \&lt;br&gt;
  --scope $(az acr show --name studentdemo3121acr --query id --output tsv)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At this point, you have a fully provisioned Azure Kubernetes cluster and a container image stored in ACR. Next, we will deploy the app into Kubernetes.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 4: Create Kubernetes Configuration&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we have our AKS cluster and image in ACR, it’s time to define the Kubernetes manifests that describe how our app should run in the cluster.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;4.1 Set Up a Manifests Directory&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Organize your Kubernetes YAML files inside a k8s folder:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd ..&lt;/code&gt; to Go back to weather-app-demo root&lt;br&gt;
&lt;code&gt;mkdir k8s&lt;/code&gt;&lt;br&gt;
&lt;code&gt;cd k8s&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jdgfcdzdds0cyeo90w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jdgfcdzdds0cyeo90w6.png" alt="Image d2w32" width="800" height="205"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;4.2 Create the Deployment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A Deployment ensures your app runs in Kubernetes with the desired number of replicas, health checks, and resource limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a file called deployment.yaml:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;touch .deployment.yaml&lt;/code&gt; - This creates a file&lt;br&gt;
 Now copy and paste the code below into the &lt;code&gt;deployment.yaml&lt;/code&gt; file created&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: weather-app
  labels:
    app: weather-app
    version: v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: weather-app
  template:
    metadata:
      labels:
        app: weather-app
        version: v1
    spec:
      containers:
      - name: weather-app
        image: studentdemo2024acr.azurecr.io/weather-app:latest
        imagePullPolicy: Always
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        env:
        - name: ASPNETCORE_ENVIRONMENT
          value: "Production"
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
        startupProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ob31j27v5knlbim3ljq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ob31j27v5knlbim3ljq.png" alt="Image d2w33" width="800" height="731"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Uses 2 replicas for high availability.&lt;/p&gt;

&lt;p&gt;Includes liveness, readiness, and startup probes to let Kubernetes know when the app is healthy.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;imagePullSecrets&lt;/code&gt; needed because AKS was created with &lt;code&gt;--attach-acr&lt;/code&gt; to handle authentication automatically!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4.3 Create the Service&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A Service exposes your app to the internet through a cloud load balancer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a file called service.yaml:&lt;/strong&gt;&lt;br&gt;
Same process we used in 4.2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: weather-app-service
  labels:
    app: weather-app
spec:
  type: LoadBalancer
  selector:
    app: weather-app
  ports:
  - name: http
    port: 80
    targetPort: 8080
    protocol: TCP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3oyabicazjto2d6xa5yx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3oyabicazjto2d6xa5yx.png" alt="Image d2w34" width="800" height="695"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4.4 Deploy to Kubernetes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Apply both manifests to your cluster:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f deployment.yaml&lt;/code&gt;&lt;br&gt;
&lt;code&gt;kubectl apply -f service.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check status:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get deployments&lt;/code&gt;&lt;br&gt;
&lt;code&gt;kubectl get pods&lt;/code&gt;&lt;br&gt;
&lt;code&gt;kubectl get services&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watch pods come online:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get pods --watch&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6uwvs9ygm3o8awpcwfjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6uwvs9ygm3o8awpcwfjl.png" alt="Image d2w35" width="800" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once ready, your service will show an external IP, use that to access the app in your browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhi4tbch5ka3xo8bqi8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhi4tbch5ka3xo8bqi8g.png" alt="Image d2w36" width="800" height="87"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fub2op9rsb9fxzjkbkvbk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fub2op9rsb9fxzjkbkvbk.png" alt="Image d2w37" width="780" height="434"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;4.5 Troubleshooting Tips&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;If you see ImagePullBackOff, debug like this:&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Describe pod to see error details&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;kubectl describe pod $(kubectl get pods -l app=weather-app -o jsonpath='{.items[0].metadata.name}')&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Verify the image exists in ACR&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;az acr repository show-tags --name studentdemo2024acr --repository weather-app --output table&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Restart deployment&lt;/strong&gt; (forces a new image pull)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;kubectl rollout restart deployment/weather-app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At this point, your app should be running on AKS and accessible from the public LoadBalancer IP.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 5: Set Up GitHub Actions CI/CD&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;With our app running in AKS, the final step is to automate deployment using GitHub Actions.&lt;br&gt;
This way, every time you push changes to your repo, GitHub will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the .NET app.&lt;/li&gt;
&lt;li&gt;Build and push a Docker image to Azure Container Registry (ACR).&lt;/li&gt;
&lt;li&gt;Update the Kubernetes deployment in AKS.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;5.1 Initialize Git Repository&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you haven’t already:&lt;/p&gt;

&lt;p&gt;cd ..  ### Back to weather-app-demo folder&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git init&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git add .&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git commit -m "Initial commit: Weather App with Docker and Kubernetes"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tuz0u0ovflxd0p9clcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tuz0u0ovflxd0p9clcy.png" alt="Image d2w38" width="800" height="660"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;5.2 Create Azure Service Principal&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;GitHub Actions needs credentials to interact with Azure. For that, we will create a Service Principal (SP).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get your subscription ID:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SUBSCRIPTION_ID=$(az account show --query id --output tsv)&lt;br&gt;
echo "Subscription ID: $SUBSCRIPTION_ID"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create the service principal:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az ad sp create-for-rbac \&lt;br&gt;
  --name "weather-app-github-sp" \&lt;br&gt;
  --role contributor \&lt;br&gt;
  --scopes /subscriptions/$SUBSCRIPTION_ID/resourceGroups/student-demo \&lt;br&gt;
  --sdk-auth&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvo04frhd1nxhhc37raua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvo04frhd1nxhhc37raua.png" alt="Image d2w39" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Important: Copy the full JSON output. You will paste it into GitHub Secrets in a moment.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;5.3 Create GitHub Repository&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can create a repo either via GitHub CLI:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gh auth login&lt;/code&gt;  ### Follow the prompts&lt;br&gt;
&lt;code&gt;gh repo create weather-app-demo --public --source=. --push&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwhe9tlpgje4moi4uz1e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwhe9tlpgje4moi4uz1e.png" alt="Image d2w40" width="800" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd184c7gi2kjxzv9flngi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd184c7gi2kjxzv9flngi.png" alt="Image d2w41" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or manually on GitHub.com → then push your local repo.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;5.4 Configure GitHub Secrets&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In your repo, go to:&lt;/p&gt;

&lt;p&gt;Settings → Secrets and variables → Actions → New repository secret&lt;/p&gt;

&lt;p&gt;Add the following secrets:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Secret Name   Value&lt;br&gt;
AZURE_CREDENTIALS   The full JSON output from Step 5.2&lt;br&gt;
ACR_NAME    studentdemo3121acr (your ACR name)&lt;br&gt;
RESOURCE_GROUP  student-demo&lt;br&gt;
CLUSTER_NAME    student-aks-cluster&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;OR configure in gh CLI&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set AZURE_CREDENTIALS (the JSON from step 5.2):
&lt;code&gt;gh secret set AZURE_CREDENTIALS&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This will open an interactive prompt where you can paste your JSON credentials from step 5.2&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the other secrets:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;gh secret set ACR_NAME --body "studentdemo3121acr"&lt;/code&gt;&lt;br&gt;
&lt;code&gt;gh secret set RESOURCE_GROUP --body "student-demo"&lt;/code&gt;&lt;br&gt;
&lt;code&gt;gh secret set CLUSTER_NAME --body "student-aks-cluster"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x1yr25rfex4fitn2f4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x1yr25rfex4fitn2f4g.png" alt="Image d2w42" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;5.5 Create GitHub Workflow&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now add the GitHub Actions workflow.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir -p .github/workflows&lt;/code&gt;&lt;br&gt;
&lt;code&gt;touch .github/workflows/deploy.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0g9yfbmeaohsm361osmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0g9yfbmeaohsm361osmw.png" alt="Image d2w43" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste the code below into .github/workflows/deploy.yml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Build and Deploy to AKS
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

env:
  IMAGE_NAME: weather-app

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '9.0.x'

      - name: Restore dependencies
        run: dotnet restore WeatherApp/WeatherAPP.csproj

      - name: Build application
        run: dotnet build WeatherApp/WeatherAPP.csproj --configuration Release --no-restore

      - name: Run tests
        run: dotnet test WeatherApp/WeatherAPP.csproj --no-build --verbosity normal || true

      - name: Azure Login
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Setup Azure CLI
        uses: azure/cli@v2
        with:
          inlineScript: echo "Azure CLI setup complete"

      - name: Build and push Docker image to ACR
        run: |
          IMAGE_TAG=${{ secrets.ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }}
          az acr build \
            --registry ${{ secrets.ACR_NAME }} \
            --image ${{ env.IMAGE_NAME }}:${{ github.sha }} \
            --file WeatherApp/Dockerfile \
            .
          echo "IMAGE_TAG=$IMAGE_TAG" &amp;gt;&amp;gt; $GITHUB_ENV

      - name: Deploy to AKS
        if: github.ref == 'refs/heads/main'
        run: |
          echo "Checking if AKS cluster exists..."
          if ! az aks show --resource-group "${{ secrets.RESOURCE_GROUP }}" --name "${{ secrets.CLUSTER_NAME }}" --output table; then
            echo "ERROR: AKS cluster '${{ secrets.CLUSTER_NAME }}' not found in resource group '${{ secrets.RESOURCE_GROUP }}'"
            exit 1
          fi

          echo "Getting AKS credentials..."
          az aks get-credentials \
            --resource-group ${{ secrets.RESOURCE_GROUP }} \
            --name ${{ secrets.CLUSTER_NAME }} \
            --overwrite-existing

          echo "Testing kubectl connection..."
          kubectl cluster-info

          echo "Updating deployment with image: ${{ env.IMAGE_TAG }}"
          kubectl set image deployment/weather-app \
            weather-app=${{ env.IMAGE_TAG }}

          echo "Waiting for rollout to complete..."
          kubectl rollout status deployment/weather-app --timeout=600s

          echo "Deployment status:"
          kubectl get pods -l app=weather-app
          kubectl get service weather-app-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vegyrmzafe1fkpgwnmp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vegyrmzafe1fkpgwnmp.png" alt="Image d2w43" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5.6 Deploy Your Application&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Commit and push:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git commit -m "Add GitHub Actions CI/CD pipeline"&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git push origin main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxeh11gi7yt32t3iezoot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxeh11gi7yt32t3iezoot.png" alt="Image d2w44" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now open your GitHub repo → Actions tab.&lt;br&gt;
You will see the workflow running, building your Docker image, pushing to ACR, and updating your AKS cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9viwwypiw5syqkgt1y8r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9viwwypiw5syqkgt1y8r.png" alt="Image d2w45" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And just like that, we have built a full CI/CD pipeline for your .NET 8 app on Azure Kubernetes Service.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 6: Access Your Deployed Application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Your app is now deployed on Azure Kubernetes Service. Let’s get the public URL so you can test it live.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;6.1 Get the External IP Address&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Check the status of your Kubernetes service:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get service weather-app-service&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You will see output like this:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NAME                 TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE&lt;br&gt;
weather-app-service  LoadBalancer   10.0.123.45    20.85.102.11    80:31000/TCP   2m&lt;/p&gt;

&lt;p&gt;👉 The EXTERNAL-IP column is what you will use.&lt;br&gt;
It may take 2–5 minutes to show up. Watch until it’s assigned:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get service weather-app-service --watch&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F631mqmh3qrdis23cxp0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F631mqmh3qrdis23cxp0n.png" alt="Image d2w46" width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylbc5i6xkswhpfjnodmv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylbc5i6xkswhpfjnodmv.png" alt="Image d2w47" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;6.2 Test Your Live Application&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once you have the external IP, test the endpoints:&lt;/p&gt;

&lt;p&gt;For the Welcome message: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl http://YOUR-EXTERNAL-IP/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft939sxvzuntbv4z2owez.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft939sxvzuntbv4z2owez.png" alt="Image d2w48" width="800" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Weather forecast:&lt;br&gt;
&lt;code&gt;curl http://YOUR-EXTERNAL-IP/weather&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fef37ebmit8m2rp23u4u5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fef37ebmit8m2rp23u4u5.png" alt="Image d2w49" width="800" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Health check:&lt;br&gt;
&lt;code&gt;curl http://YOUR-EXTERNAL-IP/health&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8zw5z5sat4z9ke5f3rav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8zw5z5sat4z9ke5f3rav.png" alt="Image d2w51" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or just open it in your browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjsvircsows6fixlvk3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjsvircsows6fixlvk3e.png" alt="Image d2w50" width="470" height="1106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpip9tu9c1m7sdkxg5d0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpip9tu9c1m7sdkxg5d0.png" alt="Image d2w52" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Swagger UI (API docs):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;open http://YOUR-EXTERNAL-IP/swagger&lt;/code&gt;   ### macOS&lt;br&gt;
&lt;code&gt;start http://YOUR-EXTERNAL-IP/swagger&lt;/code&gt;  ### Windows&lt;/p&gt;

&lt;p&gt;In macOS&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9odu5byu76rcs0hyfx81.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9odu5byu76rcs0hyfx81.png" alt="Image d2w53" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Congratulations! Your .NET 8 Weather API is now fully containerized, deployed on Kubernetes, and publicly accessible through Azure AKS.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 7: Test Continuous Deployment&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now let’s see GitHub Actions automatically deploy changes to AKS with no manual intervention required.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;7.1 Make a Code Change&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Edit &lt;code&gt;WeatherApp/Program.cs&lt;/code&gt; to update the welcome message, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.MapGet("/", () =&amp;gt; new
{
    Message = "Welcome to the Updated Weather App! 🌤️",
    Version = "1.1.0",
    Environment = app.Environment.EnvironmentName,
    Timestamp = DateTime.UtcNow,
    DeployedBy = "GitHub Actions"
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This small change is perfect to test the pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;7.2 Push the Changes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git commit -m "Update welcome message and version"&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git push origin main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzvwmc2eqtziargj2c1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzvwmc2eqtziargj2c1p.png" alt="Image d2w54" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pushing to the main branch triggers your GitHub Actions workflow automatically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkn44ex5zbk0ahcnkgk0c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkn44ex5zbk0ahcnkgk0c.png" alt="Image d2w55" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;7.3 Verify Auto-Deployment&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open your GitHub repository → Actions tab.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Watch the workflow run:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Builds the .NET app&lt;/li&gt;
&lt;li&gt;Builds &amp;amp; pushes the Docker image to ACR&lt;/li&gt;
&lt;li&gt;Updates the Kubernetes deployment in AKS&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Once completed, test your updated app:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;curl http://YOUR-EXTERNAL-IP/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffjovaykncyhv57c6poqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffjovaykncyhv57c6poqa.png" alt="Image d2w56" width="800" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see the new welcome message and updated version, confirming that CI/CD is working flawlessly as confirmed below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnfuor6xbmz9qx4df933.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnfuor6xbmz9qx4df933.png" alt="Image d2w57" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Congratulations! we have now have a fully functional CI/CD pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Push code → automatically builds, pushes, and deploys&lt;/li&gt;
&lt;li&gt;Changes reflected live in your AKS cluster&lt;/li&gt;
&lt;li&gt;All without manually logging into Azure&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Troubleshooting Guide&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Even with the best setup, things can go wrong. Here are some common issues you might face and how to fix them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pods stuck in &lt;code&gt;ImagePullBackOff&lt;/code&gt; or &lt;code&gt;ErrImagePull&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt;&lt;br&gt;
Your pods won’t start and show ImagePullBackOff.&lt;/p&gt;

&lt;p&gt;Fixes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Check pod details
kubectl describe pod $(kubectl get pods -l app=weather-app -o jsonpath='{.items[0].metadata.name}')

# Verify AKS can access your ACR
az aks check-acr \
  --resource-group student-demo \
  --name student-aks-cluster \
  --acr studentdemo2024acr.azurecr.io

# Re-attach ACR if needed
az aks update \
  --resource-group student-demo \
  --name student-aks-cluster \
  --attach-acr studentdemo2024acr

# Force pod recreation
kubectl delete pods -l app=weather-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. kubectl: command not found&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Symptoms:&lt;br&gt;
kubectl isn’t recognized.&lt;/p&gt;

&lt;p&gt;Fixes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Check if installed
kubectl version --client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If not installed, follow the official guide:&lt;br&gt;
👉 Install kubectl&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Docker daemon not running&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Symptoms:&lt;br&gt;
Docker commands fail with “Cannot connect to the Docker daemon.”&lt;/p&gt;

&lt;p&gt;Fixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start Docker Desktop&lt;/li&gt;
&lt;li&gt;Wait until the green status indicator shows&lt;/li&gt;
&lt;li&gt;Restart your terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Access denied to Azure resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Symptoms:&lt;br&gt;
Azure CLI commands fail with “unauthorized” errors.&lt;/p&gt;

&lt;p&gt;Fixes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az logout&lt;/code&gt;&lt;br&gt;
&lt;code&gt;az login&lt;/code&gt;&lt;br&gt;
&lt;code&gt;az account show&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Verify you are using the correct subscription.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. GitHub Actions pipeline failing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Check these first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All GitHub secrets are correctly set (AZURE_CREDENTIALS, ACR_NAME, etc.)&lt;/li&gt;
&lt;li&gt;The Azure service principal has Contributor access to your resource group&lt;/li&gt;
&lt;li&gt;Inspect the GitHub Actions logs for detailed error messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;6. Application not accessible via External IP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fixes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Check pods
kubectl get pods

# Check service
kubectl get services

# Inspect pod logs
kubectl logs deployment/weather-app

# Describe the service
kubectl describe service weather-app-service

**Debugging Commands**

These are useful one-liners when things don’t go as planned:

# Cluster info
kubectl cluster-info

# All resources in the namespace
kubectl get all

# Pod logs
kubectl logs -l app=weather-app

# Deployment details
kubectl describe deployment weather-app

# Node status
kubectl get nodes -o wide

# Monitor pods in real-time
kubectl get pods --watch

# ACR repositories
az acr repository list --name studentdemo2024acr --output table

# ACR image tags
az acr repository show-tags \
  --name studentdemo2024acr \
  --repository weather-app \
  --output table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ With these troubleshooting steps, you should be able to resolve most common deployment issues quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Clean Up Resources&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Once you are done experimenting, don’t forget to clean up your Azure resources otherwise, you may keep paying for unused services.&lt;/p&gt;

&lt;p&gt;You have two options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Delete Individual Resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to keep the resource group but remove specific resources:&lt;/p&gt;

&lt;h3&gt;
  
  
  Delete Kubernetes resources (Deployment + Service)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;kubectl delete -f k8s/&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Delete AKS cluster
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;az aks delete \&lt;br&gt;
  --resource-group student-demo \&lt;br&gt;
  --name student-aks-cluster \&lt;br&gt;
  --yes&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Delete Azure Container Registry (ACR)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;az acr delete \&lt;br&gt;
  --name studentdemo3121acr \&lt;br&gt;
  --yes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Option 2: Delete Everything (Recommended)&lt;/p&gt;

&lt;p&gt;If this was just a demo project, the easiest and safest way is to delete the entire resource group:&lt;/p&gt;
&lt;h3&gt;
  
  
  Delete the entire resource group (removes AKS, ACR, etc.)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;az group delete \&lt;br&gt;
  --name student-demo \&lt;br&gt;
  --yes \&lt;br&gt;
  --no-wait&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;⚠️ Note: Your GitHub repository and workflow remain intact — only Azure resources will be deleted.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What we have Accomplished&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;By following along, we have gone from zero to cloud-native hero. Here’s what we have built:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Production-Ready .NET 8 Web API&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RESTful endpoints with proper HTTP responses&lt;/li&gt;
&lt;li&gt;Health checks for monitoring&lt;/li&gt;
&lt;li&gt;Swagger documentation for easy API testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mastered Docker Containerization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-stage Docker builds for optimization&lt;/li&gt;
&lt;li&gt;Container security best practices&lt;/li&gt;
&lt;li&gt;Local testing and validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Deployed to Azure Kubernetes Service (AKS)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infrastructure as Code with Azure CLI&lt;/li&gt;
&lt;li&gt;Kubernetes manifests with proper resource requests/limits&lt;/li&gt;
&lt;li&gt;LoadBalancer service for external access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implemented CI/CD with GitHub Actions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automated build and test pipeline&lt;/li&gt;
&lt;li&gt;Container registry integration (ACR)&lt;/li&gt;
&lt;li&gt;Zero-downtime deployments with rolling updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Applied Cloud-Native Best Practices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Health, readiness, and startup probes for reliability&lt;/li&gt;
&lt;li&gt;Resource limits for efficiency&lt;/li&gt;
&lt;li&gt;Environment-specific configurations&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;📚 Next Steps&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now that you have got the foundation, here’s how you can level up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Beginner Level&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a Database: Integrate Azure SQL or PostgreSQL, use EF Core for persistence&lt;/li&gt;
&lt;li&gt;Enhance Monitoring: Add Application Insights, set up log aggregation, track custom metrics&lt;/li&gt;
&lt;li&gt;Implement Security: Add authentication with Azure AD, enable API versioning, and secure with HTTPS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Intermediate Level&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Advanced Kubernetes Features: ConfigMaps &amp;amp; Secrets, Horizontal Pod Autoscaling, Ingress controllers with custom domains&lt;/li&gt;
&lt;li&gt;Infrastructure as Code: Learn Azure Bicep or Terraform, adopt GitOps with ArgoCD, manage multiple environments&lt;/li&gt;
&lt;li&gt;Observability Stack: Prometheus &amp;amp; Grafana for metrics, Jaeger for distributed tracing, ELK stack for centralized logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You now have the skills to build, ship, and run modern .NET apps on the cloud like a pro. From here, the sky’s the limit, scale it, secure it, and make it production-grade!&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Azure Kubernetes Service (AKS) Deployment - Complete Guide Sheet&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Whether you are deploying your first .NET app to Kubernetes or need a quick refresher, this cheat sheet gives you everything you need from Docker to AKS to GitHub Actions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Concepts Explained&lt;/strong&gt;&lt;br&gt;
⚡ Kubernetes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container Orchestrator: Manages your containers like a traffic controller&lt;/li&gt;
&lt;li&gt;Scaling: Add/remove pods based on load&lt;/li&gt;
&lt;li&gt;Self-Healing: Restarts crashed pods automatically&lt;/li&gt;
&lt;li&gt;Load Balancing: Routes traffic evenly across replicas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🐳 Docker&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Containerization: Package app + dependencies&lt;/li&gt;
&lt;li&gt;Consistency: "Works on my machine" → "Works everywhere"&lt;/li&gt;
&lt;li&gt;Isolation: Each container runs independently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📦 Azure Container Registry (ACR)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private Docker Hub: Secure container storage&lt;/li&gt;
&lt;li&gt;Version Control: Track different image versions&lt;/li&gt;
&lt;li&gt;Integration: Works seamlessly with AKS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🛠️ Prerequisites&lt;br&gt;
Tool    Purpose Why You Need It&lt;br&gt;
VS Code Code Editor Write and edit code&lt;br&gt;
.NET 8 SDK  Build Tool  Compile your C# app&lt;br&gt;
Docker Desktop  Containers  Build &amp;amp; test locally&lt;br&gt;
Azure CLI   Cloud Management    Create/manage Azure resources&lt;br&gt;
kubectl Kubernetes Client   Deploy &amp;amp; manage apps on AKS&lt;br&gt;
GitHub CLI  Repo Management Create and push repos&lt;br&gt;
Git Version Control Track code changes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accounts Needed&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub → Free for repos &amp;amp; CI/CD&lt;/li&gt;
&lt;li&gt;Azure → $200 free credit to host apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Azure Infrastructure&lt;/strong&gt;&lt;br&gt;
📂 Resource Group&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az group create --name student-demo --location eastus`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resource group: Think of it as a project folder for all Azure resources&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Container Registry (ACR)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az acr create --resource-group student-demo --name studentdemo2024acr --sku Basic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Container registry is like an app store, where things can be stored, share, and download ready-to-run software packages called containers.&lt;br&gt;
Think of it like your private Docker Hub&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AKS Cluster&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az aks create --resource-group student-demo --name student-aks-cluster --node-count 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is like a managed Kubernetes cluster with auto-scaling &amp;amp; healing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.NET App Breakdown&lt;/strong&gt;&lt;br&gt;
🔑 Program.cs&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Health Checks → &lt;code&gt;app.MapHealthChecks("/health");&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Swagger → API testing UI&lt;/li&gt;
&lt;li&gt;Endpoints → &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/weather&lt;/code&gt;, &lt;code&gt;/health&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Kestrel Config&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.WebHost.ConfigureKestrel(options =&amp;gt; {
    options.ListenAnyIP(8080);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runs on port 8080 inside container&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Setup&lt;/strong&gt;&lt;br&gt;
📜 Dockerfile (multi-stage build)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Base → runtime image&lt;/li&gt;
&lt;li&gt;Build → SDK to restore &amp;amp; publish&lt;/li&gt;
&lt;li&gt;Final → small, production-ready image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;.dockerignore&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ignore &lt;code&gt;bin/&lt;/code&gt;, &lt;code&gt;obj/&lt;/code&gt;, &lt;code&gt;.git/&lt;/code&gt; → smaller, faster, more secure builds&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes Manifests&lt;/strong&gt;&lt;br&gt;
📦 deployment.yaml&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;replicas: 2 → high availability&lt;/li&gt;
&lt;li&gt;resources.requests/limits → efficient pod usage&lt;/li&gt;
&lt;li&gt;health probes → auto-healing + traffic control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;service.yaml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type: LoadBalancer
ports:
  - port: 80
    targetPort: 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exposes app with an external IP&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Actions Workflow&lt;/strong&gt;&lt;br&gt;
🔄 CI/CD Pipeline Highlights&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checkout Code → &lt;code&gt;actions/checkout@v4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Setup .NET → build/test app&lt;/li&gt;
&lt;li&gt;Azure Login → via service principal&lt;/li&gt;
&lt;li&gt;Build &amp;amp; Push Image → to ACR&lt;/li&gt;
&lt;li&gt;Deploy to AKS → update deployment, restart rollout&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Secrets Required&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AZURE_CREDENTIALS&lt;/code&gt; → Service principal JSON&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ACR_NAME&lt;/code&gt; → Your ACR name&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RESOURCE_GROUP&lt;/code&gt; → Azure resource group&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CLUSTER_NAME&lt;/code&gt; → AKS cluster name&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitoring &amp;amp; Observability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Health Checks → &lt;code&gt;HTTP 200&lt;/code&gt; = healthy&lt;/p&gt;

&lt;p&gt;Probes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Liveness → restart if dead&lt;/li&gt;
&lt;li&gt;Readiness → remove from traffic if unready&lt;/li&gt;
&lt;li&gt;Startup → delay checks until app boots&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Troubleshooting Essentials&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check Deployment → &lt;code&gt;kubectl rollout status deployment/weather-app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pod Logs → &lt;code&gt;kubectl logs &amp;lt;pod-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Service Info → &lt;code&gt;kubectl describe service weather-app-service&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Image Issues → &lt;code&gt;az acr repository show-tags --name studentdemo2024acr --repository weather-app&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quick Reference Commands&lt;/strong&gt;&lt;br&gt;
Docker&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t app:tag .
docker run -p 8080:8080 app:tag
docker logs container-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f k8s/
kubectl get pods
kubectl logs -f &amp;lt;pod-name&amp;gt;
kubectl scale deployment weather-app --replicas=3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Azure CLI&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az aks get-credentials --resource-group student-demo --name student-aks-cluster
az acr login --name studentdemo2024acr
az group delete --name student-demo --yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔥 With this guide sheet which i call cheat sheet, you have all the key commands, configs, and concepts at your fingertips for deploying .NET apps on AKS with GitHub Actions.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>tutorial</category>
      <category>kubernetes</category>
      <category>azure</category>
    </item>
    <item>
      <title>🛠️ The Full Stack DevOps Workshop</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Tue, 09 Sep 2025 11:24:52 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/the-full-stack-devops-workshop-196j</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/the-full-stack-devops-workshop-196j</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Understanding DevOps: Bridging Development and Operations&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;If you have ever built an app and thought:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do I make sure it runs the same everywhere?&lt;/li&gt;
&lt;li&gt;How can I test changes automatically?&lt;/li&gt;
&lt;li&gt;How do I go from my laptop to production safely?
…then this guide is for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this hands-on tutorial, we will walk step-by-step through setting up a complete DevOps pipeline, from writing simple Node.js code, all the way to automated CI/CD deployments with Docker and Kubernetes.&lt;/p&gt;

&lt;p&gt;By the end, you will know how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Set up Git, Docker, and GitHub Actions&lt;/li&gt;
&lt;li&gt; Write and run automated tests&lt;/li&gt;
&lt;li&gt; Build lightweight, secure Docker images&lt;/li&gt;
&lt;li&gt; Use CI/CD pipelines to test, build, and deploy automatically&lt;/li&gt;
&lt;li&gt; Deploy to staging (for testing) and production (for real users) with confidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: No prior DevOps experience required, just a willingness to code, learn, and experiment.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Hands-On Practice: Preparing Your DevOps Workspace&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  🔧 Before You Begin: Install Required Tools
&lt;/h2&gt;

&lt;p&gt;Before starting, let’s prepare your machine with the right tools:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Node.js (v18 or higher, LTS v20 recommended in 2025)&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download: &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;nodejs.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Choose the &lt;strong&gt;LTS version (20.x)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Verify installation:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; node &lt;span class="nt"&gt;--version&lt;/span&gt;
 npm &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Git (latest stable version)&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download: &lt;a href="https://git-scm.com/downloads" rel="noopener noreferrer"&gt;git-scm.com/downloads&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pick your operating system
&lt;/li&gt;
&lt;li&gt;Verify installation:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; git &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Docker Desktop (latest version)&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download: &lt;a href="https://www.docker.com/products/docker-desktop/" rel="noopener noreferrer"&gt;docker.com/products/docker-desktop&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install and start Docker Desktop
&lt;/li&gt;
&lt;li&gt;Verify installation:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; docker &lt;span class="nt"&gt;--version&lt;/span&gt;
 docker-compose &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GitHub Account&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign up: &lt;a href="https://github.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Needed for hosting your code and setting up CI/CD pipelines
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Code Editor (optional but recommended)&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suggested: &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Or use any editor you prefer (Sublime Text, Atom, etc.)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Final Check: Make Sure Everything Works
&lt;/h3&gt;

&lt;p&gt;Run these commands in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --version    # Should show v18.x+ or v20.x+  
npm --version     # Should show 9.x+ or 10.x+  
git --version     # Should show 2.34+  
docker --version  # Should show 24.x+ 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foh497k2gnhe4qzxzmnzr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foh497k2gnhe4qzxzmnzr.png" alt="Image D1" width="800" height="174"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1: Set Up Git for Version Control&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What this step does:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This tells Git who you are (your name and email) so it can label your changes. It also creates a folder for your project and starts tracking it with Git.  &lt;/p&gt;
&lt;h3&gt;
  
  
  One-time Git Setup
&lt;/h3&gt;

&lt;p&gt;Run these commands (replace with your name and email):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftapvcbdm9nots0xc86rx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftapvcbdm9nots0xc86rx.png" alt="Image D2" width="800" height="66"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create and Initialize Your Project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s create a new folder and start Git inside it by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir devops-project
cd devops-project
git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxh7hmnpxzguoaflz3lae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxh7hmnpxzguoaflz3lae.png" alt="Image D3" width="800" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2: Build a Node.js Web App&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What this step does:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We will create a simple Node.js app that serves web pages and API endpoints. This will be the foundation for our DevOps journey.  &lt;/p&gt;
&lt;h3&gt;
  
  
  1. Initialize Node.js Project
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Creates a &lt;code&gt;package.json&lt;/code&gt; file that describes your project and manages dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create package.json with default settings
`npm init -y`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running this, you will see a new package.json file in your project folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft124x6snqg1lxk5oolhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft124x6snqg1lxk5oolhm.png" alt="Image D4" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update package.json&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What it does:&lt;br&gt;
Adds scripts, metadata, and development tools to your project setup.&lt;/p&gt;

&lt;p&gt;Open the file in your editor, or create one with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Since we are using a vscode in linux &lt;code&gt;npm init -y&lt;/code&gt; has done the opening for us but had it been we are using ubuntu or a linux server we must use &lt;code&gt;touch package.json&lt;/code&gt; to open the file in the editor.&lt;/p&gt;

&lt;p&gt;So copy and paste this content in the open file editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-devops-project"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DevOps learning project with Node.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node app.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node app.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint ."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"keywords"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"devops"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodejs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your Name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"engines"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=18.0.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^29.7.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eslint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.57.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"supertest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.1.4"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9drjl5lyigx1v06uzy6l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9drjl5lyigx1v06uzy6l.png" alt="Image d6" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Create the Main Application File&lt;/strong&gt;&lt;br&gt;
What it does:&lt;br&gt;
Creates the main web server (app.js) that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listens on port 3000&lt;/li&gt;
&lt;li&gt;Serves routes: &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/health&lt;/code&gt;, &lt;code&gt;/info&lt;/code&gt;, &lt;code&gt;/metrics&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Adds security headers&lt;/li&gt;
&lt;li&gt;Supports graceful shutdown&lt;/li&gt;
&lt;li&gt;Exports the server for testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a the main application file using the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh81pea9dvu2ksk2952t5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh81pea9dvu2ksk2952t5.png" alt="Image d7" width="800" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5mxw73gglllf8w96cri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5mxw73gglllf8w96cri.png" alt="Image d8" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy this into app.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const http = require('http');
const url = require('url');
const port = process.env.PORT || 3000;
const environment = process.env.NODE_ENV || 'development';

let requestCount = 0;
const startTime = Date.now();

const server = http.createServer((req, res) =&amp;gt; {
  requestCount++;
  const timestamp = new Date().toISOString();
  const { pathname } = url.parse(req.url, true);

  console.log(`${timestamp} - ${req.method} ${pathname} - ${req.headers['user-agent'] || 'Unknown'}`);

  // CORS headers
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

  // Security headers
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-XSS-Protection', '1; mode=block');

  switch (pathname) {
    case '/':
      res.statusCode = 200;
      res.setHeader('Content-Type', 'text/html');
      res.end(`&amp;lt;h1&amp;gt;I'm Getting Better at DevOps, Yay!&amp;lt;/h1&amp;gt;`);
      break;

    case '/health':
      res.statusCode = 200;
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ status: 'healthy', uptime: process.uptime() }, null, 2));
      break;

    case '/info':
      res.statusCode = 200;
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ platform: process.platform, pid: process.pid }, null, 2));
      break;

    case '/metrics':
      res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
      res.end(`# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total ${requestCount}`);
      break;

    default:
      res.statusCode = 404;
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ error: 'Not Found' }, null, 2));
  }
});

process.on('SIGTERM', () =&amp;gt; server.close(() =&amp;gt; process.exit(0)));
process.on('SIGINT', () =&amp;gt; server.close(() =&amp;gt; process.exit(0)));

server.listen(port, () =&amp;gt; {
  console.log(`🚀 Server running at http://localhost:${port}/`);
});

module.exports = server;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs36u859ogof0meb8ky1d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs36u859ogof0meb8ky1d.png" alt="Image d8" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install Dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What it does:&lt;br&gt;
Installs the testing and linting tools your app will use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### Install testing and dev tools
npm install --save-dev jest eslint supertest

### Install all dependencies
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uya6oranc8hdydm1f0l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uya6oranc8hdydm1f0l.png" alt="Image d9" width="800" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You wll now see:&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;node_modules/&lt;/code&gt; folder with installed packages&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;package-lock.json&lt;/code&gt; file locking dependency versions&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 3: Create Proper Tests&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that your Node.js app is ready, it’s important to make sure it works every time you make changes. Automated testing lets you check your app’s endpoints without doing it manually.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a tests folder&lt;/strong&gt; → Store all your test files in one place.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write test cases&lt;/strong&gt; → Each test checks if a specific route (&lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/health&lt;/code&gt;, &lt;code&gt;/info&lt;/code&gt;, &lt;code&gt;/metrics&lt;/code&gt;) works as expected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Jest&lt;/strong&gt; → Tell Jest how to run your tests and where to store coverage reports.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this step, you will have an automated system that validates your app every time you make a change.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Creating Proper Tests&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this step does:&lt;/strong&gt;&lt;br&gt;
Sets up automated testing so your application is checked every time you make changes.  &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. Create Tests Directory and File&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### Create a folder for your tests
mkdir tests

### Create the main test file
touch tests/app.test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Write Test Cases&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;What it does:&lt;br&gt;
Checks if your web server endpoints are working correctly.&lt;/p&gt;

&lt;p&gt;Copy this code into &lt;code&gt;tests/app.test.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supertest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App Endpoints&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET / should return welcome page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DevOps Lab 2025&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET /health should return health status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/health&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;healthy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uptime&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET /info should return system info&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/info&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node_version&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET /metrics should return prometheus metrics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/metrics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http_requests_total&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app_uptime_seconds&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET /nonexistent should return 404&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/nonexistent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr47b88dqo86u7b4zqvtw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr47b88dqo86u7b4zqvtw.png" alt="Image d10" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Configure Jest&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What it does:&lt;br&gt;
Tells Jest how to run your tests and generate coverage reports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create Jest configuration file
touch jest.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuamwy3tjz7yk7pdepc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuamwy3tjz7yk7pdepc3.png" alt="Image d11" width="800" height="53"&gt;&lt;/a&gt;&lt;br&gt;
Copy this into &lt;code&gt;jest.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;testEnvironment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;collectCoverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;coverageDirectory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coverage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;testMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**/tests/**/*.test.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6g91l50v5jyf0nop67r1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6g91l50v5jyf0nop67r1.png" alt="Image d12" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 4: Add GitHub Actions for CI/CD&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of manually running tests and building Docker images, you can set up GitHub Actions. This creates a pipeline that automatically runs every time you push code to GitHub.&lt;/p&gt;

&lt;p&gt;Here’s what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tests run automatically&lt;/strong&gt; → Your app is linted, tested, and security-checked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Docker image builds automatically&lt;/strong&gt; → When changes are pushed to main, GitHub builds and pushes your Docker image to GitHub’s container registry (GHCR).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This ensures your app is always tested and ready to deploy without extra manual steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Fixed GitHub Actions CI/CD&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this step does:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Sets up an automated workflow that runs tests and builds Docker images every time you push to GitHub.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create Workflow Directory&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create the GitHub Actions directory structure
mkdir -p .github/workflows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqrp8fnp5dawubqi9tyk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqrp8fnp5dawubqi9tyk.png" alt="Image d13" width="800" height="40"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Create CI/CD Pipeline File&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create the workflow file
touch .github/workflows/ci.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy this into &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI/CD Pipeline&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;develop&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;NODE_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt;
  &lt;span class="na"&gt;REGISTRY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io&lt;/span&gt;
  &lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.repository }}&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Tests&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;18&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;20&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js ${{ matrix.node-version }}&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run linting&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx eslint . --ext .js --ignore-pattern node_modules/&lt;/span&gt;
        &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run security audit&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm audit --audit-level=moderate || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Docker Image&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name == 'push' &amp;amp;&amp;amp; github.ref == 'refs/heads/main'&lt;/span&gt;

    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
      &lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Docker Buildx&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-buildx-action@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Log in to Container Registry&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/login-action@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.REGISTRY }}&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.actor }}&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract metadata&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;meta&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/metadata-action@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}&lt;/span&gt;
          &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;type=ref,event=branch&lt;/span&gt;
            &lt;span class="s"&gt;type=sha,prefix={{branch}}-&lt;/span&gt;
            &lt;span class="s"&gt;type=raw,value=latest,enable={{is_default_branch}}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and push Docker image&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/build-push-action@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;platforms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux/amd64,linux/arm64&lt;/span&gt;
          &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.meta.outputs.tags }}&lt;/span&gt;
          &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.meta.outputs.labels }}&lt;/span&gt;
          &lt;span class="na"&gt;cache-from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type=gha&lt;/span&gt;
          &lt;span class="na"&gt;cache-to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type=gha,mode=max&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58oyxs9x448mberatrej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58oyxs9x448mberatrej.png" alt="Image d14" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 5: Create a Dockerfile&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A Dockerfile is like a recipe that tells Docker how to build a container image for your app. With this, you can run your app anywhere on your laptop, a server, or in the cloud.&lt;/p&gt;

&lt;p&gt;Here’s what this Dockerfile does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses a multi-stage build so the final image is small and efficient&lt;/li&gt;
&lt;li&gt;Installs curl for health checks&lt;/li&gt;
&lt;li&gt;Runs the app as a non-root user for better security&lt;/li&gt;
&lt;li&gt;Configures health checks to make sure the app is running&lt;/li&gt;
&lt;li&gt;Ensures proper file permissions and clean setup&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Creating a Dockerfile&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this step does:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Defines instructions for Docker to build a portable container image of your Node.js application.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. Create Dockerfile&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create the Dockerfile (no extension needed)
touch Dockerfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Add Dockerfile Content&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Copy the code below into your Dockerfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fixed and Verified Multi-stage build for optimized image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;dependencies&lt;/span&gt;

&lt;span class="c"&gt;# Update packages for security&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk upgrade &lt;span class="nt"&gt;--no-cache&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy package files first for better caching&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;

&lt;span class="c"&gt;# Install only production dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm cache clean &lt;span class="nt"&gt;--force&lt;/span&gt;

&lt;span class="c"&gt;# Production stage  &lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;production&lt;/span&gt;

&lt;span class="c"&gt;# Update packages and install necessary tools&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk upgrade &lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; curl dumb-init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/cache/apk/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="c"&gt;# Create non-root user with proper permissions&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-g&lt;/span&gt; 1001 &lt;span class="nt"&gt;-S&lt;/span&gt; nodejs &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    adduser &lt;span class="nt"&gt;-S&lt;/span&gt; nodeuser &lt;span class="nt"&gt;-u&lt;/span&gt; 1001 &lt;span class="nt"&gt;-G&lt;/span&gt; nodejs

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy dependencies from previous stage with proper ownership&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=dependencies --chown=nodeuser:nodejs /app/node_modules ./node_modules&lt;/span&gt;

&lt;span class="c"&gt;# Copy application code with proper ownership&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=nodeuser:nodejs package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=nodeuser:nodejs app.js ./&lt;/span&gt;

&lt;span class="c"&gt;# Switch to non-root user&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; nodeuser&lt;/span&gt;

&lt;span class="c"&gt;# Expose port&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;

&lt;span class="c"&gt;# Health check with proper timing for Node.js startup&lt;/span&gt;
&lt;span class="k"&gt;HEALTHCHECK&lt;/span&gt;&lt;span class="s"&gt; --interval=30s --timeout=10s --start-period=15s --retries=3 \&lt;/span&gt;
  CMD curl -f http://localhost:3000/health || exit 1

&lt;span class="c"&gt;# Use dumb-init for proper signal handling in containers&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["dumb-init", "--"]&lt;/span&gt;

&lt;span class="c"&gt;# Start application&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffetajaow9oyeuzmxgrq8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffetajaow9oyeuzmxgrq8.png" alt="Image d15" width="800" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 6: Essential Configuration Files&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Configuration files are like “rules” for your project. They tell tools what to ignore, how to check your code, and what settings to use. Adding these makes your project easier to maintain and safer to share with others.&lt;/p&gt;

&lt;p&gt;Here’s what we will add:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;.dockerignore → tells Docker which files to skip when building the container.&lt;/li&gt;
&lt;li&gt;.gitignore → tells Git which files not to track.&lt;/li&gt;
&lt;li&gt;.env.example → shows what environment variables the project needs (without secrets).&lt;/li&gt;
&lt;li&gt;.eslintrc.js → sets up ESLint to keep your code clean and consistent.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Essential Configuration Files&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this step does:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Adds important project config files to ignore unnecessary stuff, define environment settings, and enforce clean coding standards.  &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. Create &lt;code&gt;.dockerignore&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Tells Docker which files/folders to ignore when building images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch .dockerignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy this inside .dockerignore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules
npm-debug.log*
.git
.github
.env
.env.local
.env.*.local
logs
*.log
coverage
.nyc_output
.vscode
.idea
*.swp
*.swo
.DS_Store
Thumbs.db
README.md
tests/
jest.config.js
.eslintrc*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkndqo977slq4e3q8yawi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkndqo977slq4e3q8yawi.png" alt="Image d16" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Create &lt;code&gt;.gitignore&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Tells Git which files not to track in version control, by running the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the code inside &lt;code&gt;.gitignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Dependencies
node_modules/
npm-debug.log*

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

# Coverage
coverage/
.nyc_output

# Environment variables
.env
.env.local
.env.*.local

# Logs
logs
*.log

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5e1hywqrqwycw04ugfgv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5e1hywqrqwycw04ugfgv.png" alt="Image d17" width="800" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Create .env.example&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Shows other developers what environment variables your application needs, without exposing actual secrets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch .env.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy this inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Server Configuration
PORT=3000
NODE_ENV=production

# Logging
LOG_LEVEL=info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqymus08817bc8mgf6ky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqymus08817bc8mgf6ky.png" alt="Image d18" width="800" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Create .eslintrc.js&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Configures ESLint to check code quality and style.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch .eslintrc.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the code inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;es2021&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint:recommended&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;parserOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;ecmaVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sourceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-console&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-unused-vars&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;argsIgnorePattern&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;^_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsvc9blv1y3cgy6gt1oa9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsvc9blv1y3cgy6gt1oa9.png" alt="Image d19" width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 7: Docker Compose for Development&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Docker Compose is like a shortcut remote control for your app. Instead of typing long docker commands, you define everything in one file, and then just run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This makes development faster and keeps things consistent for every developer on the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Docker Compose for Development&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this step does:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Creates a &lt;code&gt;docker-compose.yml&lt;/code&gt; file that makes it easy to run your app (and later, databases) with just one command.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create Docker Compose file&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;touch docker-compose.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Copy and paste the following code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=development&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PORT=3000&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-f"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3000/health"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjhux7sjtgymye4u497t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjhux7sjtgymye4u497t.png" alt="Image d20" width="800" height="588"&gt;&lt;/a&gt;&lt;br&gt;
What this does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defines your app as a service&lt;/li&gt;
&lt;li&gt;Maps port 3000 → so you can visit &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; in your browser&lt;/li&gt;
&lt;li&gt;Sets environment variables → tells the app to run in development mode&lt;/li&gt;
&lt;li&gt;Adds a health check → ensures the app is running properly&lt;/li&gt;
&lt;li&gt;Auto restarts → if the app crashes, Docker brings it back up&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 8: Commands to Run Everything&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that your app, tests, Dockerfile, and CI/CD are ready, it’s time to run it locally and make sure everything works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install and test with npm → Installs dependencies, runs your automated tests, and starts the app.&lt;/li&gt;
&lt;li&gt;Run with Docker → Build a Docker image and run it in an isolated container.&lt;/li&gt;
&lt;li&gt;Run with Docker Compose → Start the app (and other services) together easily.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After this step, your app should be fully functional at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Commands to Run Everything&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this step does:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Shows how to run and test your Node.js application locally before deploying it.  &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. Install and Test Locally&lt;/strong&gt;
&lt;/h3&gt;
&lt;h3&gt;
  
  
  Install dependencies
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;npm install&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Run tests
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;npm test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gz06v88oxe3fjl1el7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gz06v88oxe3fjl1el7f.png" alt="Image d21" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Start application
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;npm start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9k393u01cerusvzbp11u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9k393u01cerusvzbp11u.png" alt="Image d22" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqowcafmezwk784abw0y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqowcafmezwk784abw0y.png" alt="Image d23" width="800" height="520"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### In a new terminal, test endpoints
curl http://localhost:3000/         # Homepage
curl http://localhost:3000/health   # Health check JSON
curl http://localhost:3000/info     # System info JSON
curl http://localhost:3000/metrics  # Prometheus metrics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkp2cxg6fxbkjw61cblo1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkp2cxg6fxbkjw61cblo1.png" alt="Image d24" width="800" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqug3yq2wwlxddwfqi1fc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqug3yq2wwlxddwfqi1fc.png" alt="Image d25" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Expected results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tests pass (green checkmarks)&lt;/li&gt;
&lt;li&gt;Server logs: 🚀 Server running at &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Health endpoint returns JSON: {"status":"healthy","timestamp":"...","uptime":...}&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Docker Commands&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What these commands do&lt;/strong&gt;: Build your application into a Docker container and run it in an isolated environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to run Docker commands:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Build Docker image&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;docker build -t my-devops-app:latest .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkq6geef46o3wjiazp1tr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkq6geef46o3wjiazp1tr.png" alt="Image d26" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run container&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;docker run -d \&lt;br&gt;
  --name my-devops-container \&lt;br&gt;
  -p 3000:3000 \&lt;br&gt;
  --restart unless-stopped \&lt;br&gt;
  my-devops-app:latest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylz8rraj63t505fey3qy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylz8rraj63t505fey3qy.png" alt="Image d27" width="800" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9zb7h3de28zlu79hge1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9zb7h3de28zlu79hge1.png" alt="Image d28" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check container status&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;docker ps&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5ngqrw28yvbzarvk08z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5ngqrw28yvbzarvk08z.png" alt="Image d29" width="800" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker logs my-devops-container&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2vxv1jcq9x9h3px7hxhi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2vxv1jcq9x9h3px7hxhi.png" alt="Image d30" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test health check&lt;/strong&gt;&lt;br&gt;
curl &lt;a href="http://localhost:3000/health" rel="noopener noreferrer"&gt;http://localhost:3000/health&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n2zjuovaz44ydvco9ie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n2zjuovaz44ydvco9ie.png" alt="Image d31" width="800" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop and remove container&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;docker stop my-devops-container&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6figtvcs8edqwygmwjhy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6figtvcs8edqwygmwjhy.png" alt="Image d32" width="800" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fay45lc91kmcaegmgmfv9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fay45lc91kmcaegmgmfv9.png" alt="Image d33" width="800" height="473"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;docker rm my-devops-container&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eudi4udmc6p5fgryajf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eudi4udmc6p5fgryajf.png" alt="Image d34" width="800" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgt03qryvsuy6vkchvx9u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgt03qryvsuy6vkchvx9u.png" alt="Image d35" width="800" height="464"&gt;&lt;/a&gt;&lt;br&gt;
                                                                                                                                                                                                                                                                                                                                                                                          ### &lt;strong&gt;Start all services in docker-compose.yml&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;docker-compose up -d&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68kqe3yur2preydgvfhs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68kqe3yur2preydgvfhs.png" alt="Image d36" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskolin7rcs7lu98c4pf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskolin7rcs7lu98c4pf2.png" alt="Image d37" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View logs from all services&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;docker-compose logs -f&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ovd1ahfiyd471uswie6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ovd1ahfiyd471uswie6.png" alt="Image d38" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop all services and clean up&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;docker-compose down&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjanfeepn4mdfba9rcyk2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjanfeepn4mdfba9rcyk2.png" alt="Image d39" width="800" height="100"&gt;&lt;/a&gt;&lt;br&gt;
Expected results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Containers build and start automatically&lt;/li&gt;
&lt;li&gt;Logs show your application initializing&lt;/li&gt;
&lt;li&gt;Application accessible at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 9: CI/CD with Deployment&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;What this step does:&lt;br&gt;
Pushes your local project to GitHub so the CI/CD pipeline (from Step 4) can automatically run tests, build Docker images, and deploy.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;1. Initial Commit&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Take a snapshot of your full project and save it in Git history:&lt;/p&gt;
&lt;h1&gt;
  
  
  Add all files to Git staging area
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd7qcwggxza1t2yn9bqmr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd7qcwggxza1t2yn9bqmr.png" alt="Image d40" width="800" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create your first commit with a descriptive message&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git commit -m "Initial commit: Complete DevOps setup with working CI/CD"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5lmgmpwpkozboynvibi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5lmgmpwpkozboynvibi.png" alt="Image d41" width="800" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What this does: Takes a snapshot of all your files and saves it in Git history and gets your project ready to push.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;2. Connect to GitHub&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;First, create a new repository on GitHub.com&lt;br&gt;
.&lt;br&gt;
Then link your local repo to GitHub:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set main as the default branch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git branch -M main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect to your GitHub repository (replace yourusername with your actual GitHub username)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git remote add origin https://github.com/yourusername/my-devops-project.git&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Push your code to GitHub for the first time&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;git push -u origin main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Things to know before this step &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new repo on GitHub before running these commands &lt;/li&gt;
&lt;li&gt;Copy the repo URL from GitHub (HTTPS or SSH) &lt;/li&gt;
&lt;li&gt;Replace yourusername with your actual GitHub username&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What You will See:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your project files appear in your GitHub repository&lt;/li&gt;
&lt;li&gt;GitHub Actions automatically triggers the CI/CD pipeline you configured earlier&lt;/li&gt;
&lt;li&gt;Tests, linting, security checks, and Docker builds all run in the cloud 🚀
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2etv5t3cub547azpepv1.png" alt="Image d42" width="800" height="619"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where everything comes alive:&lt;br&gt;
👉 Code → GitHub → Automated CI/CD → Ready for deployment&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylvbip1pi8mank8otmn0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylvbip1pi8mank8otmn0.png" alt="Image d42a" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;10. Step 10: Continuous Deployment (CD) Setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;What this step does:&lt;br&gt;
Extends your CI pipeline to automatically deploy your application to staging and production environments when code is pushed.&lt;/p&gt;

&lt;p&gt;⚡ &lt;strong&gt;Enhanced CI/CD Pipeline with Deployment&lt;/strong&gt;&lt;br&gt;
This enhanced pipeline will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Run tests on multiple Node.js versions&lt;/li&gt;
&lt;li&gt;🐳 Build Docker images for multiple platforms (AMD64 + ARM64)&lt;/li&gt;
&lt;li&gt;🚀 Deploy to staging when pushing to develop branch&lt;/li&gt;
&lt;li&gt;🎯 Deploy to production when pushing to main branch&lt;/li&gt;
&lt;li&gt;🔒 Run security scans on production deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🛠 &lt;strong&gt;Update Your GitHub Actions Workflow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open .github/workflows/ci.yml and replace it with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI/CD Pipeline&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;develop&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;NODE_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt;
  &lt;span class="na"&gt;REGISTRY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io&lt;/span&gt;
  &lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.repository }}&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Tests&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;18&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;20&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js ${{ matrix.node-version }}&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run linting&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx eslint . --ext .js --ignore-pattern node_modules/&lt;/span&gt;
        &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run security audit&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm audit --audit-level=moderate || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Docker Image&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name == 'push'&lt;/span&gt;

    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
      &lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

    &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image-digest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.build.outputs.digest }}&lt;/span&gt;
      &lt;span class="na"&gt;image-tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.meta.outputs.tags }}&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Docker Buildx&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-buildx-action@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Log in to Container Registry&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/login-action@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.REGISTRY }}&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.actor }}&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract metadata&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;meta&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/metadata-action@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}&lt;/span&gt;
          &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;type=ref,event=branch&lt;/span&gt;
            &lt;span class="s"&gt;type=sha,prefix={{branch}}-&lt;/span&gt;
            &lt;span class="s"&gt;type=raw,value=latest,enable={{is_default_branch}}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and push Docker image&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/build-push-action@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;platforms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux/amd64,linux/arm64&lt;/span&gt;
          &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.meta.outputs.tags }}&lt;/span&gt;
          &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.meta.outputs.labels }}&lt;/span&gt;
          &lt;span class="na"&gt;cache-from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type=gha&lt;/span&gt;
          &lt;span class="na"&gt;cache-to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type=gha,mode=max&lt;/span&gt;

  &lt;span class="na"&gt;deploy-staging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Staging&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/develop'&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to staging&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "🚀 Deploying to staging environment..."&lt;/span&gt;
          &lt;span class="s"&gt;echo "Image: ${{ needs.build.outputs.image-tag }}"&lt;/span&gt;
          &lt;span class="s"&gt;echo "Would deploy to staging server here"&lt;/span&gt;
          &lt;span class="s"&gt;# In real scenario, you'd use:&lt;/span&gt;
          &lt;span class="s"&gt;# - kubectl apply -f k8s/staging/&lt;/span&gt;
          &lt;span class="s"&gt;# - docker-compose -f docker-compose.staging.yml up -d&lt;/span&gt;
          &lt;span class="s"&gt;# - ssh staging-server "docker pull $IMAGE &amp;amp;&amp;amp; docker-compose up -d"&lt;/span&gt;

  &lt;span class="na"&gt;deploy-production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Production&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/main'&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to production&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "🎯 Deploying to production environment..."&lt;/span&gt;
          &lt;span class="s"&gt;echo "Image: ${{ needs.build.outputs.image-tag }}"&lt;/span&gt;
          &lt;span class="s"&gt;echo "Image digest: ${{ needs.build.outputs.image-digest }}"&lt;/span&gt;
          &lt;span class="s"&gt;echo "Would deploy to production server here"&lt;/span&gt;
          &lt;span class="s"&gt;# In real scenario, you'd use:&lt;/span&gt;
          &lt;span class="s"&gt;# - kubectl apply -f k8s/production/&lt;/span&gt;
          &lt;span class="s"&gt;# - terraform apply&lt;/span&gt;
          &lt;span class="s"&gt;# - ansible-playbook deploy.yml&lt;/span&gt;

  &lt;span class="na"&gt;security-scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Security Scan&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name == 'push' &amp;amp;&amp;amp; github.ref == 'refs/heads/main'&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Trivy vulnerability scanner&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aquasecurity/trivy-action@master&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;image-ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ghcr.io/kosinachi/getting-started-with-devops:latest'&lt;/span&gt;
          &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sarif'&lt;/span&gt;
          &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;trivy-results.sarif'&lt;/span&gt;

      &lt;span class="c1"&gt;# - name: Upload Trivy scan results&lt;/span&gt;
      &lt;span class="c1"&gt;#   uses: github/codeql-action/upload-sarif@v3&lt;/span&gt;
      &lt;span class="c1"&gt;#   with:&lt;/span&gt;
      &lt;span class="c1"&gt;#     # sarif_file: 'trivy-results.sarif'&lt;/span&gt;

    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;TRIVY_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.actor }}&lt;/span&gt;
      &lt;span class="na"&gt;TRIVY_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;      
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finsha0t0z9h81sr20v74.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finsha0t0z9h81sr20v74.png" alt="Image d43" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Commit and push your workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`git add .github/workflows/ci.yml`
`git commit -m "Enhance CI/CD pipeline with staging and production deployment"`
`git push origin main`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl83ugjz2mq8ijy9bi4cp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl83ugjz2mq8ijy9bi4cp.png" alt="Image d44" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3isu6zbjpurmj76qxyrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3isu6zbjpurmj76qxyrr.png" alt="Image d45" width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;☸️ Kubernetes Deployment Configurations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will now define how the app should run in staging and production.&lt;br&gt;
📦 Staging Deployment&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir -p k8s/staging&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fveyzg80c5mp6ynf8i399.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fveyzg80c5mp6ynf8i399.png" alt="Image de46" width="800" height="39"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;touch k8s/staging/deployment.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4ztmf07j3e5bm254tfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4ztmf07j3e5bm254tfn.png" alt="Image d47" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy this content into &lt;code&gt;k8s/staging/deployment.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devops-app-staging&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devops-app&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devops-app&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/yourusername/my-devops-project:develop-latest&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;staging"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PORT&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000"&lt;/span&gt;
        &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/health&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
          &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
          &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
        &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/health&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
          &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devops-app-service-staging&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devops-app&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flx2m2fb87fgiuxtav9l0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flx2m2fb87fgiuxtav9l0.png" alt="Image d48" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏭 &lt;strong&gt;Production Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir -p k8s/production&lt;/code&gt;&lt;br&gt;
&lt;code&gt;touch k8s/production/deployment.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2zcinkq85ejvmlcl8et.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2zcinkq85ejvmlcl8et.png" alt="Image d49" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy this content into &lt;code&gt;k8s/production/deployment.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: devops-app-production
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: devops-app
      environment: production
  template:
    metadata:
      labels:
        app: devops-app
        environment: production
    spec:
      containers:
      - name: app
        image: ghcr.io/yourusername/my-devops-project:latest
        ports:
        - containerPort: 3000
        env:
        - name: NODE_ENV
          value: "production"
        - name: PORT
          value: "3000"
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: devops-app-service-production
  namespace: production
spec:
  selector:
    app: devops-app
    environment: production
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
  type: LoadBalancer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8vb5jkz0jxf5qhh377u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8vb5jkz0jxf5qhh377u.png" alt="Image d50" width="800" height="574"&gt;&lt;/a&gt;&lt;br&gt;
What You will Get&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Push to develop → Staging deployed&lt;/li&gt;
&lt;li&gt;Push to main → Production deployed&lt;/li&gt;
&lt;li&gt;Automated Docker builds, tests, and security scans&lt;/li&gt;
&lt;li&gt;Kubernetes-powered scalability with replicas, probes, and resource limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 At this point, ywe have got a full DevOps pipeline from code → CI → Docker → Kubernetes → CD.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0i3wc8oehj29r9073ch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0i3wc8oehj29r9073ch.png" alt="Image d51" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 11: Complete Deployment Workflow&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;What this step does:&lt;br&gt;
Shows you how to use the full CI/CD pipeline with a proper branching strategy for staging and production deployments.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Branch-based Deployment Strategy&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Here’s how the flow works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;develop branch → 🚀 Automatically deploys to staging&lt;/li&gt;
&lt;li&gt;main branch → 🎯 Automatically deploys to production&lt;/li&gt;
&lt;li&gt;Pull Requests → ✅ Run tests only (no deployment)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures safe testing in staging before releasing to production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy Changes&lt;/strong&gt;&lt;br&gt;
👉 Deploy to Staging&lt;/p&gt;
&lt;h1&gt;
  
  
  Create and switch to develop branch
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;git checkout -b develop&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftosea0n6p19cs72nsw6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftosea0n6p19cs72nsw6k.png" alt="Image d52" width="800" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzntvdiz98rh23ovk1f5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzntvdiz98rh23ovk1f5p.png" alt="Image d54" width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Make your changes, then commit and push
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git commit -m "Add new feature"&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git push origin develop&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fze3anxxi7z4tig2idaav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fze3anxxi7z4tig2idaav.png" alt="Image d53" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyy9v3qf5b0u0hj0uec8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyy9v3qf5b0u0hj0uec8.png" alt="Image d52b" width="800" height="416"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;🔄 What happens:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GitHub Actions runs tests ✅&lt;/li&gt;
&lt;li&gt;If successful, your app is deployed to staging automatically&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Switch to main branch
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git checkout main&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Merge changes from develop
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git merge develop&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Push to trigger production deployment
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git push origin main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2selp2ipjfde1w5epnt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2selp2ipjfde1w5epnt1.png" alt="Image d55" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwrlup4dcgugqmg0ttzlp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwrlup4dcgugqmg0ttzlp.png" alt="Image d56" width="800" height="394"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;🔄 What happens:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GitHub Actions runs tests + build + security scan&lt;/li&gt;
&lt;li&gt;If successful, your app is deployed to production&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;📊 Monitor Deployments&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Check whether everything is working as expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🟢 GitHub Actions status:
👉 Your Actions page or:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### Check GitHub Actions status
### Visit: https://github.com/yourusername/my-devops-project/actions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xkgauw4vxcpk5olambi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xkgauw4vxcpk5olambi.png" alt="Image d57" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📦 Container registry:
👉 Your Docker images or:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### Check your container registry
### Visit: `https://github.com/yourusername/my-devops project/pkgs/container/my-devops-project`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpurt029wpd9g289wvnfm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpurt029wpd9g289wvnfm.png" alt="Image d58" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🧪 Test live endpoints:&lt;/p&gt;
&lt;h3&gt;
  
  
  Staging health check
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;curl https://your-staging-url.com/health&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzercnnyocwmxcninop6t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzercnnyocwmxcninop6t.png" alt="Image d59" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Production health check
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;curl https://your-production-url.com/health&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅ Expected response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "status": "healthy", "timestamp": "...", "uptime": ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🎉 At this point.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have set up a complete DevOps environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local development 🖥&lt;/li&gt;
&lt;li&gt;Containerization 🐳&lt;/li&gt;
&lt;li&gt;CI/CD pipelines ⚙️&lt;/li&gt;
&lt;li&gt;Branch-based deployments 🌿&lt;/li&gt;
&lt;li&gt;Kubernetes for staging &amp;amp; production ☸️&lt;/li&gt;
&lt;li&gt;This is a production-grade workflow you can scale for real projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Conclusion &amp;amp; Best Practices&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Congratulations! we have just built a complete DevOps pipeline, from coding locally all the way to automated staging and production deployments.&lt;/p&gt;

&lt;p&gt;This setup covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local development with Node.js + Docker&lt;/li&gt;
&lt;li&gt;Automated testing (Jest + Supertest)&lt;/li&gt;
&lt;li&gt;GitHub Actions CI/CD pipeline&lt;/li&gt;
&lt;li&gt;Secure Dockerfile and configs&lt;/li&gt;
&lt;li&gt;Kubernetes staging &amp;amp; production deployments&lt;/li&gt;
&lt;li&gt;Branch-based workflow (develop → staging, main → production)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best Practices to Keep in Mind&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Keep CI/CD Fast&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache dependencies&lt;/li&gt;
&lt;li&gt;Run tests in parallel&lt;/li&gt;
&lt;li&gt;Fail fast on errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Automate Security&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use npm audit, Trivy, or Dependabot&lt;/li&gt;
&lt;li&gt;Regularly update dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Protect Secrets&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store secrets in GitHub Actions Secrets 🔑&lt;/li&gt;
&lt;li&gt;Never commit .env files to Git&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Monitor Everything&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use /health and /metrics endpoints&lt;/li&gt;
&lt;li&gt;Connect to monitoring tools (Prometheus, Grafana, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Use Branching Wisely&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;develop → Safe place for testing&lt;/li&gt;
&lt;li&gt;main → Only stable, production-ready code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This workflow gives you a real-world DevOps setup that’s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scalable – ready for growth&lt;/li&gt;
&lt;li&gt;Secure – avoids common pitfalls&lt;/li&gt;
&lt;li&gt;Automated – less manual work, more focus on coding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From here, you can expand further by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding Terraform for infrastructure-as-code&lt;/li&gt;
&lt;li&gt;Integrating Helm charts for Kubernetes&lt;/li&gt;
&lt;li&gt;Setting up CDNs &amp;amp; load balancers for global scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You now have all the building blocks to manage modern applications like a DevOps pro!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloudcomputing</category>
      <category>github</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Exercise 4 – Configure Security Settings in Active Directory</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Sun, 24 Aug 2025 00:45:16 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/exercise-4-configure-security-settings-in-active-directory-4600</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/exercise-4-configure-security-settings-in-active-directory-4600</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;INTRODUCTION&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this exercise, you will configure security settings in Active Directory that help protect your organization from outdated authentication methods, unauthorized changes, and improper account usage.&lt;/p&gt;

&lt;p&gt;Imagine you are the IT administrator responsible for keeping your company’s network safe. Just like you wouldn’t give everyone a master key to the office or allow old locks to stay on the doors, you need to make sure your digital environment is secure.&lt;/p&gt;

&lt;p&gt;Here’s what you will do in this exercise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restrict NTLM authentication for the domain: NTLM is an older authentication method that is less secure and more vulnerable to attacks. By blocking it, you ensure that only stronger authentication methods (like Kerberos) are used in your domain.&lt;/li&gt;
&lt;li&gt;Enable auditing of user account management in the Sydney OU: This allows you to track when user accounts are created, modified, or deleted in the Sydney office. It’s like having a security camera that records who made changes, helping you detect mistakes or suspicious activity.&lt;/li&gt;
&lt;li&gt;Deny log on as a service to members of a security group: Some accounts should never be used to run background services, because if they are compromised, attackers could gain persistent access. By denying this right to certain groups, you reduce risk and enforce proper security practices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end of this exercise, you will understand how to apply practical security policies that help protect user accounts, monitor administrative activity, and prevent risky account usage. These are common tasks IT administrators perform to keep systems compliant and safe from threats.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 1 – Restrict NTLM Authentication&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here you will block NTLM authentication across the domain.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Server Manager.&lt;br&gt;
From the Tools menu, select Group Policy Management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4kiyu5lujoo7q3pszra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4kiyu5lujoo7q3pszra.png" alt="Image S1" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In Group Policy Management:&lt;/p&gt;

&lt;p&gt;Expand forest: tailwindtraders.internal → Domains → tailwindtraders.internal → Group Policy Objects.&lt;/p&gt;

&lt;p&gt;Right-click Default Domain Controller Policy → choose Edit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdewxwo6f325zmzanj54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdewxwo6f325zmzanj54.png" alt="Image S2" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the Group Policy Management Editor:&lt;/p&gt;

&lt;p&gt;Go to:&lt;br&gt;
Computer Configuration → Policies → Windows Settings → Security Settings → Local Policies → Security Options.&lt;/p&gt;

&lt;p&gt;Find and double-click:&lt;br&gt;
Network security: Restrict NTLM: NTLM authentication in this domain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71679ob5rf2cbb6b8aol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71679ob5rf2cbb6b8aol.png" alt="Image S3" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Check Define this policy setting.&lt;/p&gt;

&lt;p&gt;Select Deny all → click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ys8cxya5k9mzjc0o5av.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ys8cxya5k9mzjc0o5av.png" alt="Image S4" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
When prompted, click Yes to confirm the change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4pd3ojgt1mgdw2glagz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4pd3ojgt1mgdw2glagz.png" alt="Image S5" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Close the Group Policy Management Editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 2 – Audit User Account Management in the Sydney OU&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This sets up auditing so you can track changes made to accounts in the Sydney OU.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Server Manager.&lt;br&gt;
From the Tools menu, select Group Policy Management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyqc323lru1tv87p69vt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyqc323lru1tv87p69vt.png" alt="Image S6" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In Group Policy Management:&lt;/p&gt;

&lt;p&gt;Expand tailwindtraders.internal.&lt;/p&gt;

&lt;p&gt;Right-click the Sydney OU → select Create a GPO in this domain, and Link it here….&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss7mvnq7q81yc088kgpv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss7mvnq7q81yc088kgpv.png" alt="Image S7" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Name the new policy SydneyOUPolicy → click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fokr1rwo8qne55lpdot38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fokr1rwo8qne55lpdot38.png" alt="Image S8" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Right-click SydneyOUPolicy → select Edit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F754s06qx0fo4xv6o6sp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F754s06qx0fo4xv6o6sp0.png" alt="Image S9" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the Group Policy Management Editor:&lt;/p&gt;

&lt;p&gt;Go to:&lt;br&gt;
Computer Configuration → Policies → Windows Settings → Security Settings → Advanced Audit Policy Configuration → Audit Policies → Account Management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3qj7c2kkjtd09haw9g8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3qj7c2kkjtd09haw9g8.png" alt="Image S10" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Double-click Audit User account management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnc7kai53zafep9thuwy6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnc7kai53zafep9thuwy6.png" alt="Image S11" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Check Configure the following audit events.&lt;/p&gt;

&lt;p&gt;Select both Success and Failure → click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrj7eja8c1mslgo1wjfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrj7eja8c1mslgo1wjfe.png" alt="Image S12" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffima0m2wf9yhu15c9ym9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffima0m2wf9yhu15c9ym9.png" alt="Image 13S" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Close the Group Policy Management Editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 3 – Deny Log On As a Service&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here you will prevent members of the Sydney Administrators group from logging on as a service.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Server Manager.&lt;br&gt;
From the Tools menu, select Group Policy Management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa8wegxgkro313pyyz7jx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa8wegxgkro313pyyz7jx.png" alt="Image S14" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Expand the tailwindtraders.internal domain.&lt;/p&gt;

&lt;p&gt;Right-click SydneyOUPolicy (created earlier) → select Edit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejhybrn4pddwczvw0pqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejhybrn4pddwczvw0pqb.png" alt="Image S15" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the Group Policy Management Editor:&lt;/p&gt;

&lt;p&gt;Go to:&lt;br&gt;
Computer Configuration → Policies → Windows Settings → Security Settings → Local Policies → User Rights Assignment.&lt;/p&gt;

&lt;p&gt;Double-click Deny log on as a service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffhv8jodm1pf04c2v369.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffhv8jodm1pf04c2v369.png" alt="Image S16" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Check Define this policy setting.&lt;/p&gt;

&lt;p&gt;Click Add User or Group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklwywkr139wevfzj8syo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklwywkr139wevfzj8syo.png" alt="Image S17" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the Select Users or Groups window:&lt;/p&gt;

&lt;p&gt;Click Browse → Advanced → Find Now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cl913awl6af6zhwwfhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cl913awl6af6zhwwfhc.png" alt="Image S18" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fh1n2xihssmljnj7s4u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fh1n2xihssmljnj7s4u.png" alt="Image S19" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F762i1vbb3vl39395s3po.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F762i1vbb3vl39395s3po.png" alt="Image S20" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the Sydney Administrators group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F695b2yjkcfipz6apn2rx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F695b2yjkcfipz6apn2rx.png" alt="Image 21" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Click OK repeatedly until all windows close (about 4–5 confirmations).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52j4drnq9jt0xcbzsdd2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52j4drnq9jt0xcbzsdd2.png" alt="Image S22" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3owvv8096lobtzzlaho2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3owvv8096lobtzzlaho2.png" alt="Image S23" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys36jis1bv791xcihslk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys36jis1bv791xcihslk.png" alt="Image 24" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this exercise, you learned how to configure security settings to protect systems and user accounts from potential threats. By applying these configurations, you strengthened overall system security and ensured that users operate within a safe and controlled environment.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>tutorial</category>
      <category>azure</category>
      <category>microsoft</category>
    </item>
    <item>
      <title>Exercise 3 – Configure Group Policy for Password Policies</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Sun, 24 Aug 2025 00:38:25 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/exercise-3-configure-group-policy-for-password-policies-3891</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/exercise-3-configure-group-policy-for-password-policies-3891</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;INTRODUCTION&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this exercise, you will practice configuring important security and recovery features in Active Directory. These settings make sure that your organization’s accounts are protected and that administrators can recover objects if they’re deleted by mistake.&lt;/p&gt;

&lt;p&gt;Here’s the scenario: You are the IT administrator of a company that uses Active Directory to manage all its users and computers. To keep the company secure, you need to ensure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All users follow a standard password policy (for example, requiring a minimum length and complexity). This helps protect against simple or weak passwords that hackers could guess.&lt;/li&gt;
&lt;li&gt;Domain Administrators, who have the highest level of access, must follow an even stricter password policy because if their accounts are compromised, the entire company is at risk.&lt;/li&gt;
&lt;li&gt;If someone accidentally deletes an important account, group, or even a whole Organizational Unit (OU), you can use the Active Directory Recycle Bin to quickly restore it without starting from scratch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By completing this exercise, you will learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apply a domain-wide password policy that affects every account in the system.&lt;/li&gt;
&lt;li&gt;Create a fine-grained password policy that gives tighter security rules just to sensitive groups (like Domain Admins).&lt;/li&gt;
&lt;li&gt;Enable the Recycle Bin, a critical safety net that protects against accidental deletions and makes recovery much easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are common tasks that IT administrators perform to balance security and usability, while also preparing for mistakes that happen in real-world environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 1 – Configure Domain Password Policy&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This sets the basic password rules for the entire domain.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Server Manager.&lt;br&gt;
From the Tools menu, select Group Policy Management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonfucsm3015zfuqpw09z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonfucsm3015zfuqpw09z.png" alt="Image P1" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the Group Policy Management console:&lt;/p&gt;

&lt;p&gt;Expand forest: tailwindtraders.internal → Domains → tailwindtraders.internal.&lt;/p&gt;

&lt;p&gt;Right-click Default Domain Policy → choose Edit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhz45fdqvluzleaesgziv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhz45fdqvluzleaesgziv.png" alt="Image P2" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the Group Policy Management Editor:&lt;/p&gt;

&lt;p&gt;Go to:&lt;br&gt;
Computer Configuration → Policies → Windows Settings → Security Settings → Account Policies → Password Policy.&lt;/p&gt;

&lt;p&gt;Double-click Minimum password length.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhm21b639k3q05wbm61n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhm21b639k3q05wbm61n.png" alt="Image P3" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Change the value to 14 characters and click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fee0gu0dmgvj3w458gy8i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fee0gu0dmgvj3w458gy8i.png" alt="Image P4" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Favveat8wkw2111xz3xm0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Favveat8wkw2111xz3xm0.png" alt="Image P5" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Close the Group Policy Management Editor and then close Group Policy Management.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 2 – Configure Fine-Grained Password Policy&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This creates a stricter password rule for the Domain Admins group only.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Server Manager.&lt;br&gt;
From the Tools menu, select Active Directory Administrative Center.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfis6plrguix6s183raq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfis6plrguix6s183raq.png" alt="Image P6" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the left pane, click Tailwindtraders (local).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4fch6gi4l7f5oeedwbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4fch6gi4l7f5oeedwbg.png" alt="Image P7" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the middle pane, open the System container.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnr9e7leued3iv5bj5rhv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnr9e7leued3iv5bj5rhv.png" alt="Image P8" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Inside System, open the Password Settings Container.&lt;/p&gt;

&lt;p&gt;Right-click Password Settings Container → choose New → Password Settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4vol33y1uovfijnubwh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4vol33y1uovfijnubwh.png" alt="Image P9" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the new settings window:&lt;/p&gt;

&lt;p&gt;Name: Domain Admin Password Policy&lt;/p&gt;

&lt;p&gt;Precedence: 1&lt;/p&gt;

&lt;p&gt;Minimum password length: 16 characters&lt;/p&gt;

&lt;p&gt;Click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqh3dil8796cid5f655k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqh3dil8796cid5f655k.png" alt="Image P10" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Open the newly created policy (Domain Admin Password Policy).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0x39qzvt44r0vaaao9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0x39qzvt44r0vaaao9j.png" alt="Image P11" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the Directly Applies To section: Click Add.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0kzanhmufs7bqonh6cy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0kzanhmufs7bqonh6cy.png" alt="Image 12" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type Domain Admins.&lt;/p&gt;

&lt;p&gt;Click Check Names → OK → OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpc6z8u109d81p32cmgkx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpc6z8u109d81p32cmgkx.png" alt="Image P13" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2hxh6o53igs2agld1tn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2hxh6o53igs2agld1tn.png" alt="Image P14" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 3 – Enable Active Directory Recycle Bin&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This allows you to recover accidentally deleted AD objects (like users or OUs).&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Server Manager.&lt;br&gt;
From the Tools menu, select Active Directory Administrative Center.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F291isibt5jrloxkfv6yc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F291isibt5jrloxkfv6yc.png" alt="Image P15" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the left pane, click Tailwindtraders (local).&lt;/p&gt;

&lt;p&gt;In the right pane, select Enable Recycle Bin.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1mkpz3m9ydyjn6d6lu8h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1mkpz3m9ydyjn6d6lu8h.png" alt="Image P16" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
When a warning appears → click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mt56r03a7ll0l5q5ijc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mt56r03a7ll0l5q5ijc.png" alt="Image P17" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Another warning will appear about replication latency → click OK again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgd2aqpafwmewras139x2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgd2aqpafwmewras139x2.png" alt=" " width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this exercise, we successfully configured Group Policy for password policies, ensuring stronger protection of user accounts by enforcing rules such as password length, complexity, and expiration. These settings help maintain security across the system by reducing the risk of weak or compromised passwords.&lt;/p&gt;

&lt;p&gt;In the next exercise, we will build on this foundation by learning how to &lt;strong&gt;configure security settings&lt;/strong&gt;, which will allow us to further strengthen and customize the overall security of the system environment.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>infrastructureascode</category>
      <category>sre</category>
      <category>learning</category>
    </item>
    <item>
      <title>Exercise 2 – User Management in Active Directory</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Sun, 24 Aug 2025 00:32:58 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/exercise-2-user-management-in-active-directory-3nal</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/exercise-2-user-management-in-active-directory-3nal</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;INTRODUCTION&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this exercise, you will practice user management tasks in Active Directory. Think of Active Directory as a big digital phone book and security system for a company. It helps organize people, computers, and resources like printers into one central place, making it easier for administrators to manage everything.&lt;/p&gt;

&lt;p&gt;Imagine you are the IT administrator for a company with offices in Sydney, Melbourne, and Brisbane. Each office has its own staff, and you want to make sure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users are placed into the right Organizational Units (OUs) so they are grouped by location.&lt;/li&gt;
&lt;li&gt;Contractors and employees have their own user accounts with the right passwords and expiration dates.&lt;/li&gt;
&lt;li&gt;Special teams like Sydney Administrators have extra permissions to help manage accounts without giving them full control of everything.&lt;/li&gt;
&lt;li&gt;You can add users into groups so permissions can be given to a whole team at once rather than one person at a time.&lt;/li&gt;
&lt;li&gt;You can apply security features like Protected Users, which add extra protection to sensitive accounts.&lt;/li&gt;
&lt;li&gt;If something goes wrong, you can still audit, disable, or reset accounts when needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end of this exercise, you will be simulating what an IT admin would actually do in a real company:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up OUs for different branches of the business.&lt;/li&gt;
&lt;li&gt;Creating user accounts for contractors and assigning them to the right office.&lt;/li&gt;
&lt;li&gt;Creating a group for administrators in Sydney and giving them delegated permissions.&lt;/li&gt;
&lt;li&gt;Securing accounts by applying restrictions and ensuring compliance with company security policies.&lt;/li&gt;
&lt;li&gt;Performing everyday tasks like disabling an account when a contractor leaves or resetting a forgotten password.&lt;/li&gt;
&lt;li&gt;This hands-on scenario will help you understand not just how to do these steps in Active Directory, but also why they are important in managing users and keeping an organization secure and well-organized.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 1 – Create Organizational Units (OUs)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here we create three new OUs: Sydney, Melbourne, and Brisbane.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Server Manager.&lt;br&gt;
From the Tools menu, select Active Directory Users and Computers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsula4a30ph7dt32ivo2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsula4a30ph7dt32ivo2.png" alt="Image A" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8fai8c3fadk9yka7mq30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8fai8c3fadk9yka7mq30.png" alt="Image B" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the left panel, right-click on the tailwindtraders.internal domain.&lt;/p&gt;

&lt;p&gt;Select New → Organizational Unit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpgwdw3voo4owbkpfzyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpgwdw3voo4owbkpfzyg.png" alt="Image C" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the dialog box, type Sydney as the name and click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7b1dvknd8dvncqkjmkic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7b1dvknd8dvncqkjmkic.png" alt="Image D" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeat the same steps to create two more OUs: Melbourne and Brisbane.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9n0s55u4gw7tuhb3rbcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9n0s55u4gw7tuhb3rbcw.png" alt="Image E" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg3rdbvbpwm3dwbnygyo7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg3rdbvbpwm3dwbnygyo7.png" alt="Image F" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 2 – Create Users&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You will now create three contractor accounts (one for each city) and set properties for them.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Active Directory Users and Computers.&lt;/p&gt;

&lt;p&gt;Right-click the Sydney OU → select New → User.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fee529h6dzdlnu1toy6uc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fee529h6dzdlnu1toy6uc.png" alt="Image G" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Fill in:&lt;/p&gt;

&lt;p&gt;Full Name: SydneyContractor&lt;/p&gt;

&lt;p&gt;User Logon Name: SydneyContractor&lt;/p&gt;

&lt;p&gt;Click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhz8o64h7lw3oqyns8c8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhz8o64h7lw3oqyns8c8.png" alt="Image I" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Set the password: Pa55w.rdPa55w and confirm it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2zwco2kew81lggqvone.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2zwco2kew81lggqvone.png" alt="Image J" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Click Next → Finish.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw2e7mol258bjkn0odjv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw2e7mol258bjkn0odjv.png" alt="Image K" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Open the Sydney OU, double-click SydneyContractor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4xr0yumbsdrhot73knc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4xr0yumbsdrhot73knc.png" alt="Image L" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
On the Account tab → under Account expires, select End of: and set the date to Jan 1, 2030 → click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73gdlz6t6io8okno0w61.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73gdlz6t6io8okno0w61.png" alt="Image N" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Now, copy the SydneyContractor account:&lt;/p&gt;

&lt;p&gt;Right-click SydneyContractor → select Copy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl56gd024k1wgwx71uv5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl56gd024k1wgwx71uv5e.png" alt="Image O" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Type:&lt;/p&gt;

&lt;p&gt;Full Name: MelbourneContractor&lt;/p&gt;

&lt;p&gt;User Logon Name: MelbourneContractor&lt;/p&gt;

&lt;p&gt;Click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhn0c4i54p4oo4gume0ww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhn0c4i54p4oo4gume0ww.png" alt="Image P" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Use the password: Pa55w.rdPa55w.rd.&lt;/p&gt;

&lt;p&gt;Click Next → Finish.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3z2jopq1ifdpbzmpfd9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3z2jopq1ifdpbzmpfd9.png" alt="Image R" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Repeat the copy process again to create:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch5mrlxjgu1og4y8m2ck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch5mrlxjgu1og4y8m2ck.png" alt="Image S" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Full Name: BrisbaneContractor&lt;/p&gt;

&lt;p&gt;User Logon Name: BrisbaneContractor&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkkhe1vi1upoyulv0r3m9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkkhe1vi1upoyulv0r3m9.png" alt="Image T" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Password: Pa55w.rdPa55w.rd.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxeujezpkw4bd9hcjxjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxeujezpkw4bd9hcjxjf.png" alt="Image U" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Move users to their correct OUs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pcmsjuvr4lsir5bmoib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pcmsjuvr4lsir5bmoib.png" alt="Image W" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Drag MelbourneContractor into the Melbourne OU.&lt;/p&gt;

&lt;p&gt;If a warning pops up → click Yes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11o1vkrituhxtktptpkt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11o1vkrituhxtktptpkt.png" alt="Image X" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Drag BrisbaneContractor into the Brisbane OU.&lt;/p&gt;

&lt;p&gt;If a warning pops up → click Yes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlbjocec0las5r8hgz5r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlbjocec0las5r8hgz5r.png" alt="Image Y" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 3 – Create the Sydney Admins Group&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You will now create a security group and add a user to it.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Active Directory Users and Computers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtqgl0aen2z1ffb2tcr4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtqgl0aen2z1ffb2tcr4.png" alt="Image Z1" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Right-click the Sydney OU → select New → Group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkk09tdg8fywznvmou9mm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkk09tdg8fywznvmou9mm.png" alt="Image Z4" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Type Sydney Administrators as the group name.&lt;/p&gt;

&lt;p&gt;Set Group scope to Universal.&lt;/p&gt;

&lt;p&gt;Click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywk62aqfffea5xsit0bo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywk62aqfffea5xsit0bo.png" alt="Image Z5" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Sydney OU, double-click SydneyContractor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivjhy74h48nlyrzm4f2v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivjhy74h48nlyrzm4f2v.png" alt="Image Z2" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Go to the Member Of tab → click Add.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9qh80f41o92sbmgsft0m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9qh80f41o92sbmgsft0m.png" alt="Image Z3" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Type Sydney Administrators.&lt;/p&gt;

&lt;p&gt;Click Check Names → OK → OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bpyfvzcj3u2c0cfupf6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bpyfvzcj3u2c0cfupf6.png" alt="Image Z6" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhvbaom926lguk2qxe0c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhvbaom926lguk2qxe0c.png" alt="Image Z7" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 4 – Configure a User as a Protected User&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Active Directory Users and Computers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomgbm6a77hkxbtmkyl18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomgbm6a77hkxbtmkyl18.png" alt="Image Z8" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
In the Sydney OU, double-click SydneyContractor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19bnsc3bhqvnte172f5v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19bnsc3bhqvnte172f5v.png" alt="Image Z9" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Go to the Member Of tab → click Add.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5gz6ql1o5zleko3df92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5gz6ql1o5zleko3df92.png" alt="Image Z10" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Type Protected Users.&lt;/p&gt;

&lt;p&gt;Click Check Names → OK → OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybegynttz1zvbfextz25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybegynttz1zvbfextz25.png" alt="Image Z11" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 5 – Delegate Security Permissions to an OU&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You will allow the Sydney Administrators group to reset passwords for accounts in the Sydney OU.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Active Directory Users and Computers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fph8bss03a157ekzangxo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fph8bss03a157ekzangxo.png" alt="Image KKO" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Right-click the Sydney OU → select Delegate Control.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86mdb7vgd089rqzusypc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86mdb7vgd089rqzusypc.png" alt="Image N1" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
In the wizard:&lt;/p&gt;

&lt;p&gt;On the Welcome page → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujozb7ca30j301txa940.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujozb7ca30j301txa940.png" alt="Image N2" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Click Add, type Sydney Administrators, then click Check Names → OK → Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky0wrs5398kv6rhx06al.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky0wrs5398kv6rhx06al.png" alt="Image N3" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnzwbhgo7n6oxc9x9qlo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnzwbhgo7n6oxc9x9qlo.png" alt="Image N4" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F609dtg4cz8vndm8imect.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F609dtg4cz8vndm8imect.png" alt="Image N5" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
On the Tasks to Delegate page → select Reset user passwords and force password change at next logon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqr76s31elryj92pqwuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqr76s31elryj92pqwuw.png" alt="Image N6" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Click Next → Finish.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmurwq0k74wjmt34y1pl6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmurwq0k74wjmt34y1pl6.png" alt="Image 7N" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 6 – Configure City Attribute for a User&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Active Directory Users and Computers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9epyjkac1abyzytygx6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9epyjkac1abyzytygx6.png" alt="Image Z13" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
In the Sydney OU, right-click SydneyContractor → select Properties.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcg7wr2lqugxx0v9qeflx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcg7wr2lqugxx0v9qeflx.png" alt="Image Z14" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
In the Address tab, set City to Sydney → click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0h5krff6qfqs3pbfi23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0h5krff6qfqs3pbfi23.png" alt="Image Z15" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
To confirm:&lt;/p&gt;

&lt;p&gt;Right-click the tailwindtraders.internal domain → select Find.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwso6et1c02miaz1rpfy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwso6et1c02miaz1rpfy.png" alt="Image Z16" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
In the Advanced tab, select:&lt;/p&gt;

&lt;p&gt;Field → User → City&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0upl19lspa0o9k71dfq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0upl19lspa0o9k71dfq.png" alt="Image Z17" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Condition: Is (exactly)&lt;/p&gt;

&lt;p&gt;Value: Sydney&lt;/p&gt;

&lt;p&gt;Click Find Now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpfn3vx0jfdivwz90egc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpfn3vx0jfdivwz90egc.png" alt="Image Z18" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Click Yes when asked about searching the directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4148bt6bw6avpjgx43t2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4148bt6bw6avpjgx43t2.png" alt="Image Z19" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Make sure SydneyContractor shows up in the results.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxovzvg9fsdsmjujeurl8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxovzvg9fsdsmjujeurl8.png" alt="Image Z20" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Close the window.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 7 – Disable the Melbourne Contractor User&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Active Directory Users and Computers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felc9md2rm18zpoe2yixx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felc9md2rm18zpoe2yixx.png" alt="Image Z21" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Open the Melbourne OU.&lt;/p&gt;

&lt;p&gt;Right-click MelbourneContractor → select Disable Account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcm13lssssztj7puukcyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcm13lssssztj7puukcyq.png" alt="Image Z22" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrfy1zmvqixgmqz0upcx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrfy1zmvqixgmqz0upcx.png" alt="Image Z23" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 8 – Reset the Password of the Brisbane Contractor User&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, open Active Directory Users and Computers.&lt;/p&gt;

&lt;p&gt;Open the Brisbane OU.&lt;/p&gt;

&lt;p&gt;Right-click BrisbaneContractor → select Reset Password.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvxsl3facore7n39q2u0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvxsl3facore7n39q2u0.png" alt="Image Z24" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the new password: Pa66w.rdPa66w&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pl4vctobwyq2k39jeyz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pl4vctobwyq2k39jeyz.png" alt="Image Z25" width="800" height="426"&gt;&lt;/a&gt; twice.&lt;/p&gt;

&lt;p&gt;Click OK → then OK again on the confirmation dialog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n8lo0qu62be15sbhil7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n8lo0qu62be15sbhil7.png" alt="Image Z26" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
In this exercise, you explored how to manage users within Active Directory, including creating, modifying, and organizing user accounts. These skills are essential for ensuring proper access control and maintaining an organized directory structure in a networked environment.&lt;/p&gt;

&lt;p&gt;Now, we will move forward to the next Exercise – &lt;strong&gt;Configure Security Settings&lt;/strong&gt;, where we will focus on strengthening system protection through security configurations. Following that, we will continue with &lt;strong&gt;Exercise – Manage Password Policies&lt;/strong&gt;, which will further enhance account security by enforcing strong authentication practices.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>podcast</category>
      <category>microsoft</category>
    </item>
    <item>
      <title>Exercise 1 – Configure Domain Controller Operations</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Sun, 24 Aug 2025 00:16:54 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/exercise-1-configure-domain-controller-operations-2a5o</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/exercise-1-configure-domain-controller-operations-2a5o</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;INTRODUCTION&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this exercise, you will practice some of the core administrative tasks in Active Directory related to setting up and organizing a company’s domain environment.&lt;/p&gt;

&lt;p&gt;Imagine you are the IT administrator for a growing business that is expanding into new locations. To support this growth, you need to ensure that your Active Directory environment is structured, reliable, and ready to handle users and resources across multiple offices.&lt;/p&gt;

&lt;p&gt;Here’s what you will do in this exercise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Turn a regular server into a Domain Controller: A Domain Controller (DC) is the “brain” of Active Directory, it stores the user accounts, manages authentication, and applies security rules across the network. Promoting a server to a DC makes it part of this central system.&lt;/li&gt;
&lt;li&gt;Move a special control role (FSMO role) to the new Domain Controller: Flexible Single Master Operations (FSMO) roles are like “special duties” in the domain that only one DC can handle at a time. You will transfer one of these roles to the new DC to balance the workload and improve reliability.&lt;/li&gt;
&lt;li&gt;Create a new site: Sites in Active Directory represent physical locations, such as different office branches. By creating a site, you help AD understand the company’s network structure, which improves performance and replication efficiency.&lt;/li&gt;
&lt;li&gt;Add a subnet to the site: Subnets tell Active Directory which IP address ranges belong to which physical location. By linking a subnet to a site, you ensure that users in that office connect to the right Domain Controller.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By completing this exercise, you will learn how IT administrators prepare an Active Directory environment for growth, distribute responsibilities across servers, and organize the network to reflect the company’s real-world locations.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 1 – Install Active Directory Domain Services (AD DS) and Promote to Domain Controller&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this part, you will make the server TAILWIND-MBR1 a Domain Controller for the TAILWINDTRADERS domain.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;Sign in to TAILWIND-MBR1 as:&lt;br&gt;
Username: TAILWINDTRADERS\Administrator&lt;br&gt;
Password: Pa55w.rdPa55w or password of your choice you used&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5nc2v75lcv6voa4daso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5nc2v75lcv6voa4daso.png" alt="Pa55w.rdPa55w" width="800" height="411"&gt;&lt;/a&gt;&lt;br&gt;
In Server Manager, click Manage in the top-right menu and choose Add Roles and Features.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjh0lu5ua5802n3tforom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjh0lu5ua5802n3tforom.png" alt="Roles and Features" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the Add Roles and Features wizard:&lt;/p&gt;

&lt;p&gt;On the Before you begin page → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztwizf644jx6wd6xv13s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztwizf644jx6wd6xv13s.png" alt="click Next" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
On Select installation type → choose Role-based or feature-based installation → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10movpghj5hkio7dxow8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10movpghj5hkio7dxow8.png" alt=" " width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
On Select destination server → make sure TAILWIND-MBR1 is selected → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dr5g25tcrvlz6vfdogl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dr5g25tcrvlz6vfdogl.png" alt="TAILWIND-MBR1" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
On Select server roles → tick Active Directory Domain Services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh1bmc0t5gadenjj9pq5g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh1bmc0t5gadenjj9pq5g.png" alt=" " width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
A box pops up → click Add Features.&lt;/p&gt;

&lt;p&gt;Click Next.&lt;/p&gt;

&lt;p&gt;On Select features → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl26zawmvbmmgdi9ee8b3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl26zawmvbmmgdi9ee8b3.png" alt="features" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
On Active Directory Domain Services info page → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ubs13hviwgj982acck1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ubs13hviwgj982acck1.png" alt="info page" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
On Confirm installation selections → click Install.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvjdd28cdx2dtmi90s85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvjdd28cdx2dtmi90s85.png" alt="Install" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This may take a few minutes.&lt;/p&gt;

&lt;p&gt;When done → click Close.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvpfiqwxny9389xiooj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvpfiqwxny9389xiooj3.png" alt="click Close" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In Server Manager, click the notification flag icon in the top-right corner.&lt;br&gt;
From the notification menu, click Promote this server to a domain controller.&lt;br&gt;
This opens the Active Directory Domain Services Configuration Wizard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg3tdizlinuejc367toz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg3tdizlinuejc367toz.png" alt="top" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the wizard:&lt;/p&gt;

&lt;p&gt;On Deployment Configuration → choose Add a domain controller to an existing domain. Make sure the domain is tailwindtraders.internal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gr4etynqzo0jh499bf5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gr4etynqzo0jh499bf5.png" alt="existing domain" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will need to log in again:&lt;/p&gt;

&lt;p&gt;Click Change.&lt;br&gt;
Username: Administrator&lt;/p&gt;

&lt;p&gt;Password: Pa55w.rdPa55w.rd&lt;/p&gt;

&lt;p&gt;Click OK → Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxfgc0u2s8zj2990rf7gz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxfgc0u2s8zj2990rf7gz.png" alt=" " width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Domain Controller options:&lt;/p&gt;

&lt;p&gt;Keep the defaults.&lt;/p&gt;

&lt;p&gt;For the Directory Services Restore Mode (DSRM) password, type Pa55w.rdPa55w.rd twice.&lt;/p&gt;

&lt;p&gt;Click Next.&lt;/p&gt;

&lt;p&gt;On DNS Options → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvdhg2we1qalbdge1kc9y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvdhg2we1qalbdge1kc9y.png" alt="ifade" width="800" height="399"&gt;&lt;/a&gt;&lt;br&gt;
On Additional Options → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkqw1ru70twfxsfnu44f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkqw1ru70twfxsfnu44f.png" alt="desl" width="800" height="460"&gt;&lt;/a&gt;&lt;br&gt;
On Paths → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F55pmz3gdqkw5jlnpb3pf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F55pmz3gdqkw5jlnpb3pf.png" alt="group" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
On Review Options → click Next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhn2i30v8mdmenhnbxu21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhn2i30v8mdmenhnbxu21.png" alt="wellbeing" width="800" height="460"&gt;&lt;/a&gt;&lt;br&gt;
On Prerequisites Check → click Install.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8903wrh6kc31c60lzun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8903wrh6kc31c60lzun.png" alt="breathe" width="800" height="460"&gt;&lt;/a&gt;&lt;br&gt;
This can take a few minutes, and the server will restart automatically.&lt;/p&gt;

&lt;p&gt;When it restarts, log back in as:&lt;br&gt;
Username: tailwindtraders\administrator&lt;br&gt;
Password: Pa55w.rdPa55w.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 2 – Transfer Flexible Single Master Operations (FSMO) Role&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here you will move the RID Master role from the old Domain Controller (TAILWIND-DC1) to the new one (TAILWIND-MBR1).&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-MBR1, open Server Manager.&lt;br&gt;
Go to Tools → Active Directory Users and Computers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcvu8julnoki4oekwb1l2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcvu8julnoki4oekwb1l2.png" alt="Hook" width="800" height="460"&gt;&lt;/a&gt;&lt;br&gt;
In the left panel, right-click "Active Directory Users and Computers".&lt;br&gt;
Go to All Tasks → Operations Masters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0artnax8vfq6oxsjouyj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0artnax8vfq6oxsjouyj.png" alt="Operations" width="800" height="460"&gt;&lt;/a&gt;&lt;br&gt;
In the Operations Masters window, on the RID tab:&lt;/p&gt;

&lt;p&gt;Click Change.&lt;/p&gt;

&lt;p&gt;When asked, click Yes.&lt;/p&gt;

&lt;p&gt;Click OK.&lt;/p&gt;

&lt;p&gt;Click Close to exit the Operations Masters window.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 3 – Create an Active Directory Site and Configure a Subnet&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this part, you will create a new site called Sydney in Active Directory and then set up a subnet for it.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;p&gt;On TAILWIND-DC1, sign in as:&lt;br&gt;
Username: tailwindtraders\administrator&lt;br&gt;
Password: Pa55w.rdPa55w.rd&lt;/p&gt;

&lt;p&gt;Open Server Manager, go to Tools, and select Active Directory Sites and Services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzp75a6qu6dhyi98xk58f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzp75a6qu6dhyi98xk58f.png" alt="Tools" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
In the left panel, right-click Sites → choose New Site.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusvvkjp8apwdsjlwjf6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusvvkjp8apwdsjlwjf6d.png" alt="New Site" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
Type Sydney as the site name.For the Link Name, choose DEFAULTIPSITELINK.&lt;/p&gt;

&lt;p&gt;Click OK twice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj1zp7yrliq8o0ll0sc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj1zp7yrliq8o0ll0sc6.png" alt="OK twice" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Expand the Sites folder, Right-click Subnets → choose New Subnet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvi9kshe8is46y0ow53u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvi9kshe8is46y0ow53u.png" alt="right-click" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Prefix, type: 172.16.1.0/24&lt;/p&gt;

&lt;p&gt;For the Site name, select Sydney.&lt;/p&gt;

&lt;p&gt;Click OK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5e5i90l77501wvkinij4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5e5i90l77501wvkinij4.png" alt="gate" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Close Active Directory Sites and Services.&lt;/p&gt;

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

&lt;p&gt;In this exercise, you successfully promoted a server to a Domain Controller, transferred a FSMO role, and set up a new site with its subnet. These steps are essential for building a strong and organized Active Directory foundation that supports growth and reliability across different locations.&lt;/p&gt;

&lt;p&gt;Now that the domain structure is in place, let’s move on to the next exercise: &lt;strong&gt;Configure User Management Operations&lt;/strong&gt;, where you will learn how to create Organizational Units, users, and groups to start managing people within the domain.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>devops</category>
      <category>beginners</category>
      <category>sre</category>
    </item>
    <item>
      <title>From Setup to Management: Administering Active Directory Domain Services Like a Pro</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Sun, 24 Aug 2025 00:00:28 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/from-setup-to-management-administering-active-directory-domain-services-like-a-pro-32gp</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/from-setup-to-management-administering-active-directory-domain-services-like-a-pro-32gp</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;In this guided project, you will learn how to set up and manage Active Directory Domain Services, which is one of the most important parts of a Windows Server environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What is Active Directory?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Think of it as a big phonebook for your company’s computers and users. It helps you control who can access what, keeps your systems organized, and makes it easier to manage everything from one place.&lt;/p&gt;

&lt;p&gt;If you have ever worked in a company where you log into a computer with your work email or user ID, chances are you were using Active Directory behind the scenes.&lt;/p&gt;

&lt;p&gt;In this step-by-step guide, we will walk through the basics of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Preparing the environment and installing Install Hyper-V&lt;/li&gt;
&lt;li&gt;Setting up a domain&lt;/li&gt;
&lt;li&gt;Configure domain controller operations&lt;/li&gt;
&lt;li&gt;Configure user management operations&lt;/li&gt;
&lt;li&gt;Manage password policies&lt;/li&gt;
&lt;li&gt;Configure security settings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need to be an expert, just follow along, and by the end of this project, you will have your own mini Active Directory environment up and running.&lt;/p&gt;

&lt;p&gt;Let’s get started!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Getting Set Up for the Project&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This project is hands-on and guided — meaning you'll follow step-by-step tasks to build and manage a domain controller. Each step builds on the previous one, so it’s important to complete them in order.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What’s This Project About?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You will go through the full process of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a domain controller&lt;/li&gt;
&lt;li&gt;Configuring its settings&lt;/li&gt;
&lt;li&gt;Keeping it up and running&lt;/li&gt;
&lt;li&gt;Promoting it (giving it the authority to manage users and security)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All without needing a paid Microsoft Azure account or dedicated server hardware.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What You will Need&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To keep things budget-friendly and simple, everything runs virtually on your existing Windows 10 or 11 machine, but it must be the Pro or Enterprise edition, because only those support virtualization with Hyper-V.&lt;/p&gt;

&lt;p&gt;Here’s the basic setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Hyper-V (a built-in virtualization feature in Windows Pro/Enterprise)&lt;/li&gt;
&lt;li&gt;Create two virtual machines running Windows Server 2022 Evaluation Edition&lt;/li&gt;
&lt;li&gt;Your PC should have at least 16 GB RAM,but 8GB is still welcomed&lt;/li&gt;
&lt;li&gt;Optionally, you can use Windows Server with Hyper-V, or even a third-party virtualization tool if you prefer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: This guide uses Windows 10 pro in its examples.&lt;/p&gt;

&lt;p&gt;You will be doing three key things in the setup phase:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Hyper-V&lt;/li&gt;
&lt;li&gt;Create a virtual machine for the Domain Controller&lt;/li&gt;
&lt;li&gt;Create a second VM as a Member Server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you're done with setup, return here to continue the rest of the project. Let's get building!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Install Hyper-V&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In this task, you install Hyper-V and configure a NAT switch. You configure Hyper-V to use a different set of default directories to store virtual machine files and hard disks. You can use the options presented in these instructions or choose your own location.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign in to the Windows computer with an account that has local Administrator privileges.&lt;/li&gt;
&lt;li&gt;On the Windows Computer click on search box, then search for Turn ON and OFF manage feature.&lt;/li&gt;
&lt;li&gt;On the System page of Settings, scroll down until you locate Turn windows Features off and On.&lt;/li&gt;
&lt;li&gt;On the Optional Features page, scroll down until you locate More Windows Features under Related Settings.&lt;/li&gt;
&lt;li&gt;On the Windows Feature page, select the checkbox next to Hyper-V and click OK as shown in the exhibit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8pceqfc4kyvdygs7smfu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8pceqfc4kyvdygs7smfu.png" alt="Image A" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finalize Hyper-V Setup &amp;amp; Customize Storage Paths&lt;br&gt;
Once Hyper-V is installed, you will need to restart your computer and finish the setup by adjusting where your virtual machines and virtual hard disks (VHDs) are stored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After Installation&lt;/strong&gt;&lt;br&gt;
After the Hyper-V installation completes, click Restart Now when prompted&lt;/p&gt;

&lt;p&gt;Once your PC restarts, sign back in with your Administrator account&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set Up Hyper-V Manager&lt;/strong&gt;&lt;br&gt;
Click Start and search for Hyper-V Manager&lt;/p&gt;

&lt;p&gt;When it appears, right-click it and pin it to your Taskbar for easy access&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open Hyper-V Manager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the left pane, right-click your computer name and select Hyper-V Settings&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customize Virtual Machine Storage&lt;/strong&gt;&lt;br&gt;
Inside the Hyper-V Settings window:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29ohh0txm4c7mqgjn2d7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29ohh0txm4c7mqgjn2d7.png" alt="Image Hyper-V" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Under the Server section, click on Virtual Machines&lt;/li&gt;
&lt;li&gt;Change the default location to: C:\VirtualMachines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt5lq05baq2mp4vmjbch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt5lq05baq2mp4vmjbch.png" alt="VirtualMachines" width="722" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next, click on Virtual Hard Disks&lt;/li&gt;
&lt;li&gt;Change the location to: C:\VirtualMachines\VHDs&lt;/li&gt;
&lt;li&gt;Click OK to save your settings and close the window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj3tcdgkidvb794iqhxxh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj3tcdgkidvb794iqhxxh.png" alt="I.C" width="722" height="687"&gt;&lt;/a&gt;&lt;br&gt;
This custom setup helps you stay organized and makes it easier to clean up or move your VMs later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Set Up a NAT Network for Your Virtual Machines&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now that Hyper-V is ready, it’s time to create a NAT (Network Address Translation) network. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What this does?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This lets your virtual machines connect to the internet through your host machine, just like how your home Wi-Fi router works.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Using PowerShell&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Open PowerShell as an Administrator:&lt;/p&gt;

&lt;p&gt;Click Start, search for PowerShell&lt;/p&gt;

&lt;p&gt;Right-click it and choose Run as administrator&lt;/p&gt;

&lt;p&gt;Run the following commands to create a NAT network (copy and paste each line one at a time):&lt;br&gt;
First command Run: &lt;code&gt;New-VMSwitch -SwitchName “NATSwitch” -SwitchType Internal&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymqsoti4oromdmcsdiv1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymqsoti4oromdmcsdiv1.png" alt="IST" width="800" height="671"&gt;&lt;/a&gt;&lt;br&gt;
Second command Run: &lt;code&gt;New-NetIPAddress -IPAddress 10.10.10.1 -PrefixLength 24 -InterfaceAlias “vEthernet (NATSwitch)”&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpeiif76oziuge0i0pik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpeiif76oziuge0i0pik.png" alt="2ND" width="800" height="558"&gt;&lt;/a&gt;&lt;br&gt;
Third command Run: &lt;code&gt;New-NetNat -Name “NATNetwork” –InternalIPInterfaceAddressPrefix “10.10.10.0/24”&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1s009reshoemknip8cc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1s009reshoemknip8cc.png" alt="3RD" width="740" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Create Windows Server Domain Controller Virtual Machine&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Next up, is deploying a Windows Server 2022 Domain Controller we will set up the heart of your lab: a Windows Server 2022 Domain Controller. This is the server that will manage your domain like user logins, security settings, and more.&lt;/p&gt;

&lt;p&gt;Download the ISO File&lt;br&gt;
To get started, download the Windows Server 2022 Evaluation Edition ISO from Microsoft:&lt;/p&gt;

&lt;p&gt;Download from Microsoft 👉 &lt;code&gt;https://www.microsoft.com/en-us/evalcenter/download-windows-server-2022&lt;/code&gt;&lt;br&gt;
After download save the file in a folder called &lt;code&gt;C:\ISOs&lt;/code&gt; on your machine&lt;/p&gt;

&lt;p&gt;This ISO gives you access to the full version of Windows Server 2022 free to use for 180 days&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why use the Evaluation Edition?&lt;/strong&gt; It’s perfect for learning, testing, and lab environments like this one — no license required upfront.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Create the Domain Controller Virtual Machine (TAILWIND-DC1)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now it's time to spin up your first virtual machine: This one will act as your Domain Controller, the central brain of your lab environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s how to do it using Hyper-V Manager:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step: Create the VM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open Hyper-V Manager&lt;/li&gt;
&lt;li&gt;In the Actions panel (on the right), click New &amp;gt; Virtual Machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faao1w4hzl5pd6kas6849.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faao1w4hzl5pd6kas6849.png" alt="click New" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the wizard that opens:&lt;/li&gt;
&lt;li&gt;Click Next on the Before You Begin page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwb896sixdoprnuknexl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwb896sixdoprnuknexl.png" alt="NEXT" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the Name and Location page:&lt;/li&gt;
&lt;li&gt;Set the name to TAILWIND-DC1&lt;/li&gt;
&lt;li&gt;Click Next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumkuzjx7wb2i72jggw5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumkuzjx7wb2i72jggw5h.png" alt="Next" width="704" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the Generation page, select Generation 2, then Next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl5g45fdsjs0ubmkoyem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl5g45fdsjs0ubmkoyem.png" alt="Generation page" width="704" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the Memory page:&lt;/li&gt;
&lt;li&gt;Set Startup Memory to according to memory availiable for you to assign but not less than 2000 mb&lt;/li&gt;
&lt;li&gt;Keep "Use Dynamic Memory" checked&lt;/li&gt;
&lt;li&gt;Click Next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41aantkb7tt079gbpg9z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41aantkb7tt079gbpg9z.png" alt="memory" width="704" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the Networking page:&lt;/li&gt;
&lt;li&gt;Choose NATSwitch from the dropdown menu&lt;/li&gt;
&lt;li&gt;Click Next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw04wb7p8ejrkn4vphz2o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw04wb7p8ejrkn4vphz2o.png" alt="Natswitch" width="704" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the Virtual Hard Disk page:&lt;/li&gt;
&lt;li&gt;Accept the default settings and click Next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqufygg8ra71tujas4ik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqufygg8ra71tujas4ik.png" alt="Default" width="704" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the Installation Options page:&lt;/li&gt;
&lt;li&gt;Select "Install an operating system from a bootable image file"&lt;/li&gt;
&lt;li&gt;Click Browse and choose the Windows Server 2022 Evaluation ISO located in C:\ISOs (usually named SERVER_EVAL_x64FRE_en-us.iso)&lt;/li&gt;
&lt;li&gt;Click Next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Froq34atezqggceqsfuhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Froq34atezqggceqsfuhc.png" alt="BROWSE" width="704" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the Summary page, click Finish&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59cchxiv5ncgkfd6sv5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59cchxiv5ncgkfd6sv5j.png" alt="FINISH" width="704" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Disable Automatic Checkpoints&lt;/strong&gt;&lt;br&gt;
Once the VM is created:&lt;/p&gt;

&lt;p&gt;In Hyper-V Manager, right-click TAILWIND-DC1 and choose Settings&lt;/p&gt;

&lt;p&gt;Under Management, select Checkpoints&lt;/p&gt;

&lt;p&gt;Make sure "Use automatic checkpoints" is unchecked&lt;/p&gt;

&lt;p&gt;Click OK to save&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh74bgehbkmlx0jcve4ba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh74bgehbkmlx0jcve4ba.png" alt="SAVE" width="722" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔒 Why disable automatic checkpoints? It keeps things cleaner and prevents Hyper-V from creating snapshot-style backups that could eat up disk space during testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Boot Up and Begin Installing Windows Server 2022&lt;/strong&gt;&lt;br&gt;
Now that your virtual machine (TAILWIND-DC1) is created, it’s time to install Windows Server 2022 from the ISO file you attached earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start the VM and Begin Installation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Hyper-V Manager, double-click TAILWIND-DC1 to open the Virtual Machine Connection window&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj273i5xwqjllycixsb91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj273i5xwqjllycixsb91.png" alt="WINDOW" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click Start (the green button on the toolbar) to power on the VM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ohkcwc3rkt8el4wnqck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ohkcwc3rkt8el4wnqck.png" alt="START" width="640" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quickly watch for the message:&lt;/li&gt;
&lt;li&gt;"Press any key to boot from CD or DVD..."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqg82aawda0bf95wgi48n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqg82aawda0bf95wgi48n.png" alt=" " width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you see it, click inside the VM window to focus, then press the tab key to highlight &lt;code&gt;Restart Now&lt;/code&gt; and make it clickable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bbb0ibzaymwm9d36iye.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bbb0ibzaymwm9d36iye.png" alt="clickable" width="800" height="594"&gt;&lt;/a&gt;&lt;br&gt;
This tells the VM to boot from the ISO file you selected earlier&lt;/p&gt;

&lt;p&gt;Begin Windows Server Setup&lt;br&gt;
On the Microsoft Server Operating System Setup screen:&lt;/p&gt;

&lt;p&gt;Leave all default settings as-is and click Next&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiy2ynxg8id6k96s6abfz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiy2ynxg8id6k96s6abfz.png" alt=" " width="800" height="594"&gt;&lt;/a&gt;&lt;br&gt;
On the next screen, click Install now&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrwb0qd976ctkr18t8v8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrwb0qd976ctkr18t8v8.png" alt=" " width="800" height="594"&gt;&lt;/a&gt;&lt;br&gt;
When asked to choose an edition: Select Windows Server 2022 Standard Evaluation (Desktop Experience) and Click Next&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqrhtd240isfayx6fdbf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqrhtd240isfayx6fdbf.png" alt="Click Next" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🪟 "Desktop Experience" gives you the full Windows GUI, ideal for hands-on learning and managing the server more easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Install Windows Server 2022 and Promote It to a Domain Controller&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that your VM is ready and the ISO is mounted, it’s time to install Windows Server 2022 and turn it into a fully functional Domain Controller.&lt;/p&gt;

&lt;p&gt;Finish Installing Windows Server&lt;br&gt;
On the license terms screen, check “I Accept” and click Next&lt;/p&gt;

&lt;p&gt;When asked about the type of installation, choose Custom&lt;/p&gt;

&lt;p&gt;On the disk selection screen, pick Drive 0 and click Next&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1y4brmdy3c013ibky2b3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1y4brmdy3c013ibky2b3.png" alt="Drive 0" width="800" height="594"&gt;&lt;/a&gt;&lt;br&gt;
The OS will install and reboot, this may take several minutes&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiaezne1gxc1wyalo8hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiaezne1gxc1wyalo8hg.png" alt="install and reboot" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click on connect&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fug7gkxulap6d9jlpn0p7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fug7gkxulap6d9jlpn0p7.png" alt="click on connect" width="800" height="594"&gt;&lt;/a&gt;&lt;br&gt;
When prompted to set the Administrator password, enter:&lt;code&gt;Password1&lt;/code&gt;&lt;br&gt;
(Use your own if you prefer, but this demo password works for the lab.)&lt;/p&gt;

&lt;p&gt;After setup completes, log in with the Administrator account using the password above.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Set Static IP for the VM&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;On the VM, right-click the network icon (a globe) in the taskbar → choose Open Network &amp;amp; Internet Settings&lt;/p&gt;

&lt;p&gt;Click Change adapter options&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1j7ofa31wm5uxu7oq3d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1j7ofa31wm5uxu7oq3d.png" alt="adapter" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Right-click Ethernet → select Properties&lt;/p&gt;

&lt;p&gt;Double-click Internet Protocol Version 4 (TCP/IPv4)&lt;/p&gt;

&lt;p&gt;Enter the following static IP settings:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;IP Address:        10.10.10.10  &lt;br&gt;
Subnet Mask:       255.255.255.0  &lt;br&gt;
Default Gateway:   10.10.10.1  &lt;br&gt;
DNS (Preferred):   1.1.1.1  &lt;br&gt;
DNS (Alternate):   8.8.8.8&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Click OK, then Close. When prompted to allow network discovery, choose Yes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rename the Server&lt;/strong&gt;&lt;br&gt;
Open Server Manager → click Local Server&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6z631kq9qv9ib1x9jzzb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6z631kq9qv9ib1x9jzzb.png" alt="manager" width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
Next to Computer Name, click the name to open System Properties&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwvwk5u1tnxehztutn5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwvwk5u1tnxehztutn5i.png" alt="Coadapter" width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
Click Change, then set the name to:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3qpvljcty804o6odn6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3qpvljcty804o6odn6k.png" alt="Change" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs83lazu8harplzjoz6qr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs83lazu8harplzjoz6qr.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;TAILWIND-DC1&lt;/code&gt;&lt;br&gt;
Click OK and Restart Now when prompted&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikk6lwksolvdp3kdueo7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikk6lwksolvdp3kdueo7.png" alt="prompted" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Log back in as Administrator&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Install Active Directory Domain Services (AD DS)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In Server Manager, go to Manage → Add Roles and Features&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftco7cwuk57g62ql9hkve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftco7cwuk57g62ql9hkve.png" alt="descript" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf5apyzogj3j5a8f7h42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf5apyzogj3j5a8f7h42.png" alt="des" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click Next through the following screens:&lt;/p&gt;

&lt;p&gt;Before you begin&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8pt6uxqwzylt8aicpl2z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8pt6uxqwzylt8aicpl2z.png" alt="begin" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Select installation type → choose Role-based or feature-based&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kn6tygi0kpnofwu0ycd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kn6tygi0kpnofwu0ycd.png" alt="feature-based" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Select destination server → ensure TAILWIND-DC1 is selected&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx29slyckuvznxt09xymb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx29slyckuvznxt09xymb.png" alt="cription" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
On Select server roles:&lt;/p&gt;

&lt;p&gt;Check Active Directory Domain Services&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf3u8rmbfnvm84y45ojv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf3u8rmbfnvm84y45ojv.png" alt=" " width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
Click Add Features when prompted&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjazu0zcdacolzkpeo577.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjazu0zcdacolzkpeo577.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
Click Next until you reach the Confirmation page&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbupwg720ny80f2mana9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbupwg720ny80f2mana9e.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgucc7gjln9byd1d5ea2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgucc7gjln9byd1d5ea2.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftns35cztrhuzsw6c5v23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftns35cztrhuzsw6c5v23.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click Install&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqnbnv2ilu3gqboeflta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqnbnv2ilu3gqboeflta.png" alt="Iription" width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
This may take a few minutes.&lt;/p&gt;

&lt;p&gt;To promote the Server to a Domain Controller:&lt;br&gt;
In Server Manager, click the flag icon in the top-right corner&lt;/p&gt;

&lt;p&gt;Click Promote this server to a domain controller&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgproptsae7horuepzdf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgproptsae7horuepzdf.png" alt=" " width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the wizard:&lt;/p&gt;

&lt;p&gt;On Deployment Configuration, choose Add a new forest&lt;/p&gt;

&lt;p&gt;Set the root domain name to: &lt;code&gt;tailwindtraders.internal&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F16ur55768zrya72xh641.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F16ur55768zrya72xh641.png" alt="donae" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Domain Controller Options, leave defaults, but enter this DSRM password twice:&lt;code&gt;Password1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgsnr2lxv4qyfhx42zilo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgsnr2lxv4qyfhx42zilo.png" alt="password" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click Next through the DNS, Additional Options, and Paths screens&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtgnur916f4jypjq0bow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtgnur916f4jypjq0bow.png" alt="Imdescription" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop6gxvtkwd9m4272ug8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop6gxvtkwd9m4272ug8s.png" alt="tion" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Review Options, click Next&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5n2rtp06ljwqzhkglyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5n2rtp06ljwqzhkglyl.png" alt="Review" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Prerequisites Check, click Install&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F923xy4hqa3kv30je0dlt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F923xy4hqa3kv30je0dlt.png" alt="iption" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl751yypud8sij6bvqo3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl751yypud8sij6bvqo3.png" alt="automatically" width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
The server will restart automatically when done.&lt;/p&gt;

&lt;p&gt;Final Login&lt;br&gt;
After the restart, log in using your new domain credentials:&lt;/p&gt;

&lt;p&gt;Username: &lt;code&gt;tailwindtraders\administrator&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Password: &lt;code&gt;Password1&lt;/code&gt;&lt;br&gt;&lt;br&gt;
You now have a working Active Directory Domain Controller running in a virtual environment, all from a Windows 11 machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Create Windows Server Domain Member Server&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create Virtual Machine (TAILWIND-MBR1) in Hyper-V
Open Hyper-V Manager &amp;gt; Actions &amp;gt; New &amp;gt; Virtual Machine&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsaa2ht0t90ex0x98i7ur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsaa2ht0t90ex0x98i7ur.png" alt="Virtual Machine" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On before you begin page click next&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjo72dbxwcahfomuhkapx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjo72dbxwcahfomuhkapx.png" alt="begin" width="704" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Name: TAILWIND-MBR1 click next&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gpbi3xozuvsypez1pgn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gpbi3xozuvsypez1pgn.png" alt=" " width="704" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Generation: 2 click next&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepdytfdvoneh9e3ckr7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepdytfdvoneh9e3ckr7x.png" alt=" " width="704" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Memory: 4096 MB (Dynamic Memory enabled) choose any memory of your choice and click next&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hcl69r42zmzkuvkw34d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hcl69r42zmzkuvkw34d.png" alt="2GB" width="704" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Networking: NATSwitch and click next&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F647st9xql3l76ovbbdtf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F647st9xql3l76ovbbdtf.png" alt=" " width="704" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Virtual Hard Disk: Accept defaults&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcs8f3pa1ubpzf5sfuix3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcs8f3pa1ubpzf5sfuix3.png" alt="defaults" width="704" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Install an OS from a bootable image file click on browse look for*&lt;em&gt;ISO&lt;/em&gt;*:File: C:\ISOs\SERVER_EVAL_x64FRE_en-us.iso&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuxuh7aod46xgfkzmwxz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuxuh7aod46xgfkzmwxz.png" alt="ISO" width="704" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Click on finish&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgaat3hs08jl6ii84x0vf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgaat3hs08jl6ii84x0vf.png" alt="finished " width="704" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Configure VM Settings&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Right-click VM &amp;gt; Settings &amp;gt; Management &amp;gt; Checkpoints&lt;/p&gt;

&lt;p&gt;Uncheck: Use automatic checkpoints&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvc3fz3sllpi9hat499zn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvc3fz3sllpi9hat499zn.png" alt="automatic checkpoints" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Install Windows Server&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Double tap on TAILWIND-MBR1 → Start VM → Press any key to boot from ISO&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1lt9l439teskazhugl1u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1lt9l439teskazhugl1u.png" alt="start" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2nohpd2eth5wc4gcf9h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2nohpd2eth5wc4gcf9h.png" alt="press" width="642" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqie86rpt1oyy9099ki1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqie86rpt1oyy9099ki1s.png" alt="anykey" width="800" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzu1w8hbdtox5srf3qeee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzu1w8hbdtox5srf3qeee.png" alt="tap" width="800" height="586"&gt;&lt;/a&gt;&lt;br&gt;
Accept default language/keyboard settings &amp;gt; Next &amp;gt; Install now&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ih6kpugifae9qzszmjb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ih6kpugifae9qzszmjb.png" alt="keyboard settings" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbau4lyzj5stq7kslejm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbau4lyzj5stq7kslejm.png" alt="Install now" width="800" height="594"&gt;&lt;/a&gt;&lt;br&gt;
Select version: Windows Server 2022 Standard Evaluation (Desktop Experience)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo2zeo47w1gv19b9ee19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo2zeo47w1gv19b9ee19.png" alt="Select version" width="800" height="594"&gt;&lt;/a&gt;&lt;br&gt;
Accept license terms&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7h09aemjx3td4sl8pbb1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7h09aemjx3td4sl8pbb1.png" alt="license terms" width="800" height="594"&gt;&lt;/a&gt;&lt;br&gt;
Choose: Custom installation and Select Drive 0 &amp;gt; Click Next&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feldnsahj9sqmw3nxi0ky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feldnsahj9sqmw3nxi0ky.png" alt="Custom installation" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait for OS installation to complete&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffz7yqkumu28cdiritwyz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffz7yqkumu28cdiritwyz.png" alt="OS installation" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Set Administrator Password&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Use password: Pa55w.rdPa55w.rd or choose any password of your choice&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hq2c57lzwpvtz2eo3wr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hq2c57lzwpvtz2eo3wr.png" alt="choose any password" width="800" height="594"&gt;&lt;/a&gt;&lt;br&gt;
Log in to VM after setup completes&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnakjr9sunsfszezuwjj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnakjr9sunsfszezuwjj8.png" alt="login" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Configure Network Settings&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Right-click network icon &amp;gt; Open Network &amp;amp; Internet Settings&lt;/p&gt;

&lt;p&gt;Click Change adapter options &amp;gt; Right-click Ethernet &amp;gt; Properties&lt;/p&gt;

&lt;p&gt;Select Internet Protocol Version 4 (TCP/IPv4) &amp;gt; Properties&lt;/p&gt;

&lt;p&gt;Set the following manually:&lt;/p&gt;

&lt;p&gt;IP Address: 10.10.10.20&lt;/p&gt;

&lt;p&gt;Subnet Mask: 255.255.255.0&lt;/p&gt;

&lt;p&gt;Default Gateway: 10.10.10.1&lt;/p&gt;

&lt;p&gt;DNS: 10.10.10.10 (Preferred), 8.8.8.8 (Alternate)&lt;/p&gt;

&lt;p&gt;Click OK &amp;gt; Close &amp;gt; Select "Yes" when prompted to allow discovery&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6. Rename Computer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Open Server Manager &amp;gt; Local Server &amp;gt; Computer Name&lt;/p&gt;

&lt;p&gt;Click Change &amp;gt; Rename to: TAILWIND-MBR1&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhtyficjm1gsctdhrz976.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhtyficjm1gsctdhrz976.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Restart the computer&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;7. Join Domain&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;After reboot, log in as Administrator using the password you created&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3vakwckd2x8z4xlazqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3vakwckd2x8z4xlazqb.png" alt="Administrator" width="800" height="458"&gt;&lt;/a&gt;&lt;br&gt;
Go to Server Manager &amp;gt; Local Server &amp;gt; Computer Name &amp;gt; Change&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frosbzzi4l7gc9pp2dty0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frosbzzi4l7gc9pp2dty0.png" alt=" " width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under Member of, choose Domain: TAILWINDTRADERS&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3ppxbuycm92rycsl94z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3ppxbuycm92rycsl94z.png" alt=" " width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Credentials:&lt;/p&gt;

&lt;p&gt;Username: TAILWINDTRADERS\Administrator&lt;/p&gt;

&lt;p&gt;Password: Pa55w.rdPa55w.rd&lt;/p&gt;

&lt;p&gt;Click OK &amp;gt; Confirm domain join &amp;gt; Restart VM&lt;/p&gt;

&lt;p&gt;You have now successfully created and configured a Windows Server 2022 domain member server named TAILWIND-MBR1 and joined it to the TAILWINDTRADERS domain.&lt;/p&gt;

</description>
      <category>activedirectory</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>microsoft</category>
    </item>
    <item>
      <title>Getting Started with Kubernetes on Minikube: Deploy, Explore, Expose, Scale, and Update Your App</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Thu, 17 Jul 2025 21:03:38 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/getting-started-with-kubernetes-on-minikube-deploy-explore-expose-scale-and-update-your-app-4oga</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/getting-started-with-kubernetes-on-minikube-deploy-explore-expose-scale-and-update-your-app-4oga</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;INTRODUCTION&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;What is Kubernetes?&lt;br&gt;
In simple terms Kubernetes is like a traffic controller for your apps.&lt;br&gt;
For example imagine you have a bunch of shipping containers, each with part of your app inside (like a website, a database, an API, etc.). These containers need to run on servers. But managing all of them manually, starting them, stopping them, moving them if something breaks is a pain. So Kubernetes is the system that takes care of all that automatically. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does for you:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Starts your app for you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keeps it running if something crashes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Puts it on the best available server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then create more copies of it if needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why Use Kubernetes?&lt;/strong&gt;&lt;br&gt;
Think of Kubernetes like the manager of a busy restaurant kitchen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You (the app owner) give the manager a recipe (your deployment file).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The manager (Kubernetes) decides how many cooks (containers) to assign.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If one cook burns out (a pod crashes), the manager replaces them automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If a lot of customers show up (high traffic), the manager brings in more cooks (auto-scaling).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you want to change the recipe (new app version), the manager makes the switch smoothly so customers don’t even notice (rolling updates).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt;&lt;br&gt;
Using Kubernetes means you can spend less time fixing broken stuff and more time building your app. It handles the boring, repetitive parts of running apps in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Things you need to get you started is:&lt;/strong&gt;&lt;br&gt;
Docker installed, basic CLI knowledge, Minikube or similar kind setup, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Module 1 - Create a Kubernetes Cluster&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this module, we will set up a local Kubernetes cluster for development purposes using Minikube. This allows you to run and test Kubernetes workloads on your own machine without needing a cloud provider.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 – Start Your Local Kubernetes Cluster&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We will begin by launching a local Kubernetes cluster using Minikube. This creates a single node cluster on your machine, which acts like a small, self-contained version of a full Kubernetes setup. It gives you a safe environment to experiment, deploy apps, and learn how Kubernetes works all without needing internet access or a cloud account.&lt;/p&gt;

&lt;p&gt;If you haven’t installed Minikube yet, go ahead and install it first at &lt;a href="https://minikube.sigs.k8s.io/docs/start/?arch=%2Fmacos%2Fx86-64%2Fstable%2Fbinary+download#Service" rel="noopener noreferrer"&gt;https://minikube.sigs.k8s.io/docs/start/?arch=%2Fmacos%2Fx86-64%2Fstable%2Fbinary+download#Service&lt;/a&gt;. Once that’s done, you can confirm it was installed correctly by running the following command in your terminal: &lt;code&gt;minikube version&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov61yo5izrt6xw0b2vbn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov61yo5izrt6xw0b2vbn.png" alt="minikube version" width="800" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once Minikube is installed, you can start your local Kubernetes cluster by running the following command: &lt;code&gt;minikube start&lt;/code&gt;&lt;br&gt;
This command sets up a single-node cluster on your machine, which will act as your personal Kubernetes environment for development and testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvc6rpt2941tsmv8jlc0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvc6rpt2941tsmv8jlc0w.png" alt="minikube version" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Good! we now have a running Kubernetes cluster on our machine.&lt;br&gt;
Minikube has created a virtual environment for us and launched a single-node Kubernetes cluster inside it. This environment behaves just like a real Kubernetes setup, letting you deploy and manage applications locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 – Check the Cluster Version&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To interact with your Kubernetes cluster, we will use the command-line tool called kubectl. It’s the main way we will manage and communicate with our cluster.&lt;/p&gt;

&lt;p&gt;Do not worry we will go deeper into how kubectl works later, but for now, let’s use it to view some basic information about the cluster.&lt;/p&gt;

&lt;p&gt;First, check that kubectl is installed and working by running: &lt;code&gt;kubectl version&lt;/code&gt;&lt;br&gt;
This command will show the version details for both the client (our machine) and the server (the Kubernetes cluster running in Minikube).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3yzma01zmcbe0lb83a8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3yzma01zmcbe0lb83a8.png" alt="kubectl version" width="800" height="62"&gt;&lt;/a&gt;&lt;br&gt;
As you can see kubectl is now configured correctly!&lt;br&gt;
When you run kubectl version, you will see two main pieces of information:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Client Version: This is the version of the kubectl tool installed on your machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server Version: This is the version of Kubernetes running on your Minikube cluster (specifically on the master node).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 – View Cluster Details&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now that our cluster is up and running, let’s take a look at some basic information about it.&lt;/p&gt;

&lt;p&gt;You can do this by running the following command: &lt;code&gt;kubectl cluster-info&lt;/code&gt;&lt;br&gt;
This command shows important details about your Kubernetes cluster, such as the URL of the Kubernetes control plane (also known as the API server) and other key components running inside the cluster.&lt;/p&gt;

&lt;p&gt;It’s a quick way to confirm that your cluster is active and responding to commands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvvuv2ytoero04h2cfrp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvvuv2ytoero04h2cfrp.png" alt="kubectl cluster-info" width="800" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Throughout this tutorial, we will mainly use the command line to deploy and explore our application.&lt;/p&gt;

&lt;p&gt;To see the nodes available in your Kubernetes cluster, run:&lt;br&gt;
&lt;code&gt;kubectl get nodes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1dlhwk10dsf4qvj68biw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1dlhwk10dsf4qvj68biw.png" alt="kubectl get nodes" width="800" height="55"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This command lists all the nodes that your cluster can use to run applications.&lt;br&gt;
Since we are using Minikube, you’ll see just one node, the local virtual machine Minikube started for us.&lt;/p&gt;

&lt;p&gt;As you can see the node's status says Ready, that means it’s healthy and available to run our apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Module 2 – Deploying Your First App&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this section, you'll learn how to deploy your first application on Kubernetes using the kubectl command-line tool.&lt;/p&gt;

&lt;p&gt;The goal is to get hands-on experience with the basic kubectl commands and understand how to interact with your app once it’s running in the cluster. You will see how easy it is to launch, inspect, and manage applications with just a few commands.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 – Getting Started with kubectl&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To begin working with Kubernetes from the command line, we will use a tool called kubectl.&lt;/p&gt;

&lt;p&gt;You can type the following in your terminal to see a list of available commands: &lt;code&gt;kubectl&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqw2oub35lh7g1nuzzhpf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqw2oub35lh7g1nuzzhpf.png" alt="kubectl" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The typical format of a kubectl command looks like this: &lt;code&gt;kubectl &amp;lt;action&amp;gt; &amp;lt;resource&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;action&lt;/code&gt;: What you want to do (e.g., create, get, describe)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;resource&lt;/code&gt;: What you are acting on (e.g., pods, nodes, deployments)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get more details about any command, you can add the &lt;code&gt;--help&lt;/code&gt; flag. For example: &lt;code&gt;kubectl get nodes --help&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flx44vriuggmo454aaupd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flx44vriuggmo454aaupd.png" alt="kubectl get nodes" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check Your Setup&lt;/strong&gt;&lt;br&gt;
To make sure kubectl is properly set up to talk to your Kubernetes cluster, run: &lt;code&gt;kubectl version&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This should show both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client Version – the version of kubectl on your machine&lt;/li&gt;
&lt;li&gt;Server Version – the version of Kubernetes running in your Minikube cluster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;View Your Nodes&lt;/strong&gt;&lt;br&gt;
Now let’s check the node(s) in the cluster:&lt;code&gt;kubectl get nodes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgheibum83yfh6aamq3cj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgheibum83yfh6aamq3cj.png" alt="kubectl get nodes" width="800" height="133"&gt;&lt;/a&gt;&lt;br&gt;
This command lists the available nodes. Since we are using Minikube, you will only see one node. Kubernetes will use this node to schedule and run your application based on the resources it has available (like CPU and memory).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 – Deploying Your App&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s go ahead and deploy your first application on Kubernetes using the kubectl create deployment command.&lt;/p&gt;

&lt;p&gt;This command needs two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A name for your deployment.&lt;/li&gt;
&lt;li&gt;The image you want to deploy (this is the container that runs your app, include the full repository url for images hosted outside Docker Hub).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the command: &lt;code&gt;kubectl create deployment kubernetes-bootcamp --image=gcr.io/k8s-minikube/kubernetes-bootcamp:v1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foby8pflta8rqnegfd1ed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foby8pflta8rqnegfd1ed.png" alt="kubectl create" width="800" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What just happened?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By running that single command, Kubernetes did a lot behind the scenes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Found a suitable node to run your app (we only have one, so it chose that one).&lt;/li&gt;
&lt;li&gt;Started the app inside a container on that node.&lt;/li&gt;
&lt;li&gt;Set things up so that if the container crashes or the node fails, Kubernetes will automatically restart or reschedule it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;View Your Deployment&lt;/strong&gt;&lt;br&gt;
To see the list of active deployments, run: &lt;code&gt;kubectl get deployments&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxqulvwviiwjzukifmh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxqulvwviiwjzukifmh0.png" alt="kubectl get deployment" width="800" height="130"&gt;&lt;/a&gt;&lt;br&gt;
You will see one deployment running, this is your app, and it’s running inside a Docker container managed by Kubernetes.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 – Viewing Your App Inside the Cluster&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By default, applications (called Pods) running in Kubernetes are on a private network. This means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They can talk to each other inside the cluster.&lt;/li&gt;
&lt;li&gt;But they are not accessible from the outside, including your browser or host machine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When we use kubectl, we are talking to the Kubernetes API server, which acts as a bridge between us and the cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a Temporary Connection (Using a Proxy)&lt;/strong&gt;&lt;br&gt;
We will explore how to make your app publicly accessible in Module 4, but for now, we can use kubectl proxy to temporarily connect to your app from your local machine.&lt;/p&gt;

&lt;p&gt;This proxy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lets your terminal access the cluster’s internal API endpoints.&lt;/li&gt;
&lt;li&gt;Doesn’t show output while running.&lt;/li&gt;
&lt;li&gt;Can be stopped anytime with &lt;code&gt;Control + C&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To keep things organized, it’s best to open a second terminal window or tab, and run: &lt;code&gt;echo -e "Starting Proxy. After starting it will not output a response. Please return to your original terminal window\n"; kubectl proxy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqq5w0q4h68p5fky7bvae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqq5w0q4h68p5fky7bvae.png" alt="kubectl proxy" width="800" height="84"&gt;&lt;/a&gt;&lt;br&gt;
This sets up a connection from your local terminal to the Kubernetes cluster via port &lt;code&gt;8001&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing the Proxy with curl&lt;/strong&gt;&lt;br&gt;
Now that the proxy is running, you can test it by accessing the Kubernetes API.&lt;br&gt;
In your original terminal, run: &lt;code&gt;curl http://localhost:8001/version&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhoq1mvtxiqn9bv9ycxs3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhoq1mvtxiqn9bv9ycxs3.png" alt="original terminal" width="800" height="431"&gt;&lt;/a&gt;&lt;br&gt;
Note: The proxy was run in a new tab, and the recent commands were executed in the original tab. The proxy still runs in the second tab, and this allowed our curl command to work using localhost:8001.&lt;/p&gt;

&lt;p&gt;⚠️ If this doesn’t work, make sure &lt;code&gt;kubectl proxy&lt;/code&gt; is still running in your second terminal tab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessing Your Pod Through the API&lt;/strong&gt;&lt;br&gt;
Kubernetes gives every Pod a unique endpoint through the API.&lt;br&gt;
To access it, you first need to get your Pod’s name and we will store in the environment variable POD_NAME:&lt;/p&gt;

&lt;p&gt;Run this in your original terminal:&lt;code&gt;export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')&lt;br&gt;
echo Name of the Pod: $POD_NAME&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdry1er41x0nmvan1kr7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdry1er41x0nmvan1kr7.png" alt="POD_NAME" width="800" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can access the Pod through the API by running: &lt;code&gt;curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxrzzyybj13wxstijasl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxrzzyybj13wxstijasl.png" alt="Access pod" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note on Public Access&lt;/strong&gt;&lt;br&gt;
Right now, this setup only works through the proxy (on localhost:8001).&lt;br&gt;
If you want your app to be accessible without using a proxy, for example, from a browser or external system then you will need to create a Service, which we will cover in the next module.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Module 3 – Exploring Your App&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this module, you will learn how to inspect and troubleshoot applications running in Kubernetes using a few key kubectl commands:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;kubectl get&lt;/code&gt; – List resources like pods, services, deployments.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl describe&lt;/code&gt; – Show detailed information about a specific resource.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl logs&lt;/code&gt; – View the output (logs) from inside a container.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl exec&lt;/code&gt; – Run commands inside a running container, like you’re SSH-ing into it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These tools are essential for debugging and understanding what’s going on inside your cluster when something doesn’t seem right, or when you just want to confirm everything is working correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 – Check if Your App is Running&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To verify that your application is up and running, we will use the kubectl get command to check for existing Pods.&lt;/p&gt;

&lt;p&gt;In your terminal, run: &lt;code&gt;kubectl get pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotgje5185a4lmp6lkz3p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotgje5185a4lmp6lkz3p.png" alt="kubectl get pods" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This command lists all the Pods currently running in your cluster. You should see one Pod, the one created by your deployment in the previous module.&lt;/p&gt;

&lt;p&gt;Also you can see a status like saying Running in the output. That means the application is successfully running inside the Pod.&lt;/p&gt;

&lt;p&gt;To get a deeper look into what's happening inside your Pod, like what containers it's running, what image it's using, and its configuration you can use the kubectl describe command: &lt;code&gt;kubectl describe pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fam88tkuitg7v4wmzo5kv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fam88tkuitg7v4wmzo5kv.png" alt="kubectl describe pod" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This command shows detailed information about your Pod, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The container image being used&lt;/li&gt;
&lt;li&gt;The Pod's internal IP address&lt;/li&gt;
&lt;li&gt;Ports that are exposed&lt;/li&gt;
&lt;li&gt;Events related to the Pod’s lifecycle (like when it started or if there were any errors)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output can be a bit long and may include concepts we haven’t covered yet but don’t worry. As you move through this article, everything will start to make more sense.&lt;/p&gt;

&lt;p&gt;Tip: kubectl describe works with many types of Kubernetes resources (like nodes, pods, and deployments) and is meant to be human readable, not used for scripting.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 – View Your App in the Terminal&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As a reminder, Pods in Kubernetes run inside a private network, they are isolated from the outside world. To interact with a Pod directly (for debugging or testing), we need a way to access that internal network.&lt;/p&gt;

&lt;p&gt;We will do this by using &lt;code&gt;kubectl proxy&lt;/code&gt;, which creates a temporary connection between your local machine and the Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start the Proxy&lt;/strong&gt;&lt;br&gt;
Open a second terminal window and run this command: &lt;code&gt;echo -e "Starting Proxy. After starting it will not output a response. Please return to your original terminal window\n"; kubectl proxy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7u06wus0epz9ke0rma5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7u06wus0epz9ke0rma5.png" alt="kubectl proxy" width="800" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this command does?&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It starts a local proxy server on port 8001.&lt;/li&gt;
&lt;li&gt;It runs silently (no output) and stays active until you press Control + C to stop it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Get the Pod Name&lt;/strong&gt;&lt;br&gt;
Back in your original terminal, run the following to get the name of your Pod and store it in an environment variable: &lt;code&gt;export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')&lt;br&gt;
echo Name of the Pod: $POD_NAME&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkmp4y0y7u5oza45oj5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkmp4y0y7u5oza45oj5c.png" alt="echo" width="800" height="53"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This sets a variable called POD_NAME with the name of the Pod that’s running your app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query the Pod Using curl&lt;/strong&gt;&lt;br&gt;
Now that the proxy is running and we have the Pod name, we can make a direct request to the Pod’s API using: &lt;code&gt;curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykhi8g21h2k9y993bafd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykhi8g21h2k9y993bafd.png" alt="curl" width="800" height="1211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This command above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sends a request through the proxy&lt;/li&gt;
&lt;li&gt;Reaches into the Kubernetes cluster&lt;/li&gt;
&lt;li&gt;Returns details about your running Pod&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a great way to see your application’s internal state directly from the terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 – View the Logs from Your Container&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In Kubernetes, any output your application sends to standard output (STDOUT) becomes part of the container logs. This is useful for checking what your app is doing, debugging issues, or just seeing printed messages (like logs or errors).&lt;/p&gt;

&lt;p&gt;To view the logs from your running container, use this command: &lt;code&gt;kubectl logs $POD_NAME&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwprck7pt1ixcry7cb0o6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwprck7pt1ixcry7cb0o6.png" alt="pod name" width="800" height="45"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since there’s only one container inside the Pod, you don’t need to specify the container name, Kubernetes knows which one to fetch logs from.&lt;/p&gt;

&lt;p&gt;This command will show you everything the app has printed since it started, just like &lt;code&gt;console.log&lt;/code&gt;, &lt;code&gt;print()&lt;/code&gt;, or &lt;code&gt;System.out.println()&lt;/code&gt; in a normal app.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4 – Running Commands Inside the Container&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once your Pod is up and running, you can interact directly inside the container, that is almost like SSH-ing into a running app. This is helpful for debugging, inspecting files, or running manual tests.&lt;br&gt;
&lt;strong&gt;Check Environment Variables&lt;/strong&gt;&lt;br&gt;
Let’s start by running a simple command to list all environment variables inside the container: &lt;code&gt;kubectl exec $POD_NAME -- env&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje3hg40o77dmqbj2g0hc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje3hg40o77dmqbj2g0hc.png" alt="inside the contanier" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This uses &lt;code&gt;kubectl exec&lt;/code&gt; to execute the &lt;code&gt;env&lt;/code&gt; command inside your Pod.&lt;/p&gt;

&lt;p&gt;Since our Pod only has one container, we don’t need to specify its name, because kubernetes knows which one to target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start a Shell Session (Bash)&lt;/strong&gt;&lt;br&gt;
To open a live terminal inside the container, run: &lt;code&gt;kubectl exec -ti $POD_NAME -- bash&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx3bcfxslltecns73fg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx3bcfxslltecns73fg5.png" alt="shell session" width="694" height="64"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;-ti&lt;/code&gt; allows you to run in interactive mode (just like SSH).&lt;/li&gt;
&lt;li&gt;You are now inside the container’s shell and can run commands as if you were on a Linux server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;View the App Source Code&lt;/strong&gt;&lt;br&gt;
Your app is a simple Node.js app. You can check the source code by running: &lt;code&gt;cat server.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3o8mum1ncapw2ju6wv94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3o8mum1ncapw2ju6wv94.png" alt="cat server" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see it printed the contents of the server.js file that’s running in the container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test the Running App&lt;/strong&gt;&lt;br&gt;
While still inside the container, test that the app is responding by curling localhost: &lt;code&gt;curl localhost:8080&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpcop47stcbscmc1z3zv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpcop47stcbscmc1z3zv.png" alt="curl localhost" width="800" height="43"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should get a response from the app, as seen above usually the same one you'd see if it were exposed in a browser.&lt;/p&gt;

&lt;p&gt;Note: We use localhost here because you're inside the Pod’s network. If this doesn’t work, doublecheck that you're running the command inside the container shell.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exit the Container&lt;/strong&gt;&lt;br&gt;
When you’re done, type:&lt;code&gt;exit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbebh5inpwaj734bk7aq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbebh5inpwaj734bk7aq.png" alt="exit" width="778" height="98"&gt;&lt;/a&gt;&lt;br&gt;
This will close the shell and return you to your local terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Module 4 – Expose Your App to the Outside World 🌍&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this module, we will learn how to make your application accessible outside the Kubernetes cluster, so it’s no longer limited to just internal access.&lt;/p&gt;

&lt;p&gt;Here’s what we’ll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to expose your app using the kubectl expose command&lt;/li&gt;
&lt;li&gt;How to label Kubernetes resources using the kubectl label command (labels help group and organize your resources)
By the end of this module, you’ll have your Node.js app reachable via a public URL and you’ll understand how to apply custom tags (labels) to your deployments and Pods.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 – Expose Your App by Creating a Service&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Until now, your application has only been running inside the Kubernetes cluster, which means it’s not accessible from the outside world.&lt;/p&gt;

&lt;p&gt;In this step, we’ll expose the app publicly using a Service of type &lt;code&gt;NodePort&lt;/code&gt;, which opens a port on the cluster’s Node and allows external traffic to reach your app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check if Your App is Still Running&lt;/strong&gt;&lt;br&gt;
Run this command to make sure the Pod is active: &lt;code&gt;kubectl get pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7q6qbvp65osg12vheaw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7q6qbvp65osg12vheaw5.png" alt="kubectl get pods" width="800" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;List Current Services&lt;/strong&gt;&lt;br&gt;
Kubernetes might already have some default Services (like one for DNS). Run: &lt;code&gt;kubectl get services&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3w3ljt1kcs2uedou489.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3w3ljt1kcs2uedou489.png" alt="get services" width="800" height="138"&gt;&lt;/a&gt;&lt;br&gt;
You’ll probably see a &lt;code&gt;kubernetes&lt;/code&gt; service created automatically by Minikube.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expose Your App with a New Service&lt;/strong&gt;&lt;br&gt;
Now let’s create a new Service that exposes our app externally on port 8080: &lt;code&gt;kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhghekj26gnsg4lfjfnp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhghekj26gnsg4lfjfnp.png" alt="expose" width="800" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This creates a new service and maps it to the deployment we created earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check That the New Service Was Created&lt;/strong&gt;&lt;br&gt;
Run: &lt;code&gt;kubectl get services&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbh5602ttgzml1ywicslk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbh5602ttgzml1ywicslk.png" alt="get sservices" width="800" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should now see a new service called kubernetes-bootcamp.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It has a Cluster IP (internal network address).&lt;/li&gt;
&lt;li&gt;It also has a NodePort, which makes it accessible from outside the cluster.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Docker Desktop Users (Important Note)&lt;br&gt;
If you're using Docker Desktop instead of Minikube, accessing NodePorts directly may not work due to networking restrictions.&lt;/p&gt;

&lt;p&gt;Instead, run this command: &lt;code&gt;minikube service kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfl6g8earjt8dkysgjn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfl6g8earjt8dkysgjn7.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see this command will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open a browser window with your app&lt;/li&gt;
&lt;li&gt;Create an SSH tunnel from the Node to your host&lt;/li&gt;
&lt;li&gt;Allow access to your app externally&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To close the tunnel, just hit Control + C.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get the External Port (NodePort)&lt;/strong&gt;&lt;br&gt;
Let’s find out the actual port Kubernetes opened to the outside: &lt;br&gt;
&lt;code&gt;kubectl describe services/kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fif3w1mwoxzkqxf77bud9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fif3w1mwoxzkqxf77bud9.png" alt="Bootcamp" width="800" height="542"&gt;&lt;/a&gt;&lt;br&gt;
Create an environment variable called NODE_PORT that has the value of the Node port assigned: &lt;code&gt;export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')&lt;br&gt;
echo NODE_PORT=$NODE_PORT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vf9kg7kksc2zr6owcmr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vf9kg7kksc2zr6owcmr.png" alt="Node port" width="800" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Access the App from Your Host Machine&lt;/strong&gt;&lt;br&gt;
Now test your app using &lt;code&gt;curl&lt;/code&gt;, combining Minikube’s IP address with the external port: &lt;code&gt;curl $(minikube ip):$NODE_PORT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If everything is set up correctly, you should see a response from your Node.js app!&lt;/p&gt;

&lt;p&gt;Congratulations!!!! our app is now publicly accessible!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 – Using Labels in Kubernetes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When we created our app using a Deployment, Kubernetes automatically added a label to the Pod. Labels are like name tags, they help us group, filter, and organize resources inside the cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check the Pod label:&lt;/strong&gt;&lt;br&gt;
We can look at the deployment details to see which labels were added: &lt;code&gt;kubectl describe deployment&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fki415gl7cd2nf3tr0h81.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fki415gl7cd2nf3tr0h81.png" alt="kubectl describe" width="800" height="606"&gt;&lt;/a&gt;&lt;br&gt;
You'll see something like &lt;code&gt;app=kubernetes-bootcamp&lt;/code&gt; listed under Labels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use the label to find the Pod:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that we know the label, we can use it to search for our Pod:&lt;br&gt;
&lt;code&gt;kubectl get pods -l app=kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98b0idcxc3wu41tzlqqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98b0idcxc3wu41tzlqqf.png" alt="app=kubernates" width="800" height="94"&gt;&lt;/a&gt;&lt;br&gt;
The command above tells Kubernetes:&lt;/p&gt;

&lt;p&gt;“Show me all the Pods that have the label &lt;code&gt;app=kubernetes-bootcamp&lt;/code&gt;.”&lt;/p&gt;

&lt;p&gt;You can do the same thing for services: &lt;code&gt;kubectl get services -l app=kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffuuae4dl8c63fyhma70g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffuuae4dl8c63fyhma70g.png" alt="kubernates bootcamp" width="800" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Store the Pod name:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s grab the Pod’s name and store it in a variable so we can use it easily in the next commands: &lt;code&gt;export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')&lt;br&gt;
echo Name of the Pod: $POD_NAME&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg2h76etqzc2n3ymcp5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg2h76etqzc2n3ymcp5j.png" alt="pod name" width="800" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add a new label to the Pod:&lt;/strong&gt;&lt;br&gt;
We can attach a custom label to the Pod. In this case, we’re labeling the version of the app: &lt;code&gt;kubectl label pods $POD_NAME version=v1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtrncxs879hob6e8g71c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtrncxs879hob6e8g71c.png" alt="labelled" width="766" height="84"&gt;&lt;/a&gt;&lt;br&gt;
This adds a label &lt;code&gt;version=v1&lt;/code&gt; to the Pod — super useful for organizing and managing deployments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check if the new label was applied:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s confirm the label is attached: &lt;code&gt;kubectl describe pods $POD_NAME&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyeevd36lvnpt8t3ukgv7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyeevd36lvnpt8t3ukgv7.png" alt="metadata" width="800" height="853"&gt;&lt;/a&gt;&lt;br&gt;
You’ll now see the new label listed under the Pod’s metadata.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filter using the new label:&lt;/strong&gt;&lt;br&gt;
Now that we added the version=v1 label, We see here that the label is attached new to our Pod. Now we can use it to filter the Pod list: &lt;code&gt;kubectl get pods -l version=v1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr19zei4mqsvdtzjkrjpn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr19zei4mqsvdtzjkrjpn.png" alt="version=v1" width="800" height="107"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is helpful when you have lots of Pods and want to target only specific ones, for example, by version, environment (&lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;prod&lt;/code&gt;), or anything else you define with labels.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 – Deleting a Kubernetes Service&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now that we have exposed our app using a Service, let’s learn how to delete that Service when we no longer need it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Delete the service:&lt;/strong&gt;&lt;br&gt;
We can remove the Service using the following command. It uses the same label we applied earlier: &lt;code&gt;kubectl delete service -l app=kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8u4gzve5sxhsg0fbuqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8u4gzve5sxhsg0fbuqq.png" alt="delete" width="800" height="108"&gt;&lt;/a&gt;&lt;br&gt;
This tells Kubernetes: Delete any Service that has the label &lt;code&gt;app=kubernetes-bootcamp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make sure the Service is gone:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After deletion, confirm it with: &lt;code&gt;kubectl get services&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxc5od27fv27x5qnvp8w0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxc5od27fv27x5qnvp8w0.png" alt=" " width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see that the custom Service is no longer listed, just the default Kubernetes service remains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test if the app is still exposed:&lt;/strong&gt;&lt;br&gt;
Try accessing the app from outside the cluster using the IP and NodePort you used earlier: &lt;code&gt;curl $(minikube ip):$NODE_PORT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You’ll get an error now and that’s expected!&lt;/p&gt;

&lt;p&gt;This shows that the app is no longer exposed to the outside world and that the route is closed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check if the app is still running inside the cluster:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even though the service is gone, the app is still running internally. We can confirm that by sending a request from inside the Pod: &lt;code&gt;kubectl exec -ti $POD_NAME -- curl localhost:8080&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1n36pa5sogpjcz74antm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1n36pa5sogpjcz74antm.png" alt="respond" width="800" height="108"&gt;&lt;/a&gt;&lt;br&gt;
And wow, you should see the app respond.&lt;/p&gt;

&lt;p&gt;This is because your Deployment is still running and managing the app inside Kubernetes. The Pod exists, but without a Service, it’s not reachable from outside.&lt;/p&gt;

&lt;p&gt;Optional: Want to completely stop the app?&lt;/p&gt;

&lt;p&gt;To shut it all down not just make it private you’d need to delete the Deployment too. That would stop the app entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Module 5 – Scale Up Your App&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this module, we will learn how to increase the number of running copies (called replicas) of our app using Kubernetes. This is known as scaling.&lt;/p&gt;

&lt;p&gt;Why scale?&lt;br&gt;
Let’s say your app starts getting more traffic. One Pod (a running instance of your app) might not be enough to handle all the requests. So, we tell Kubernetes to run more Pods like hiring extra workers for a busy day.&lt;/p&gt;

&lt;p&gt;When you scale up, Kubernetes automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates more Pods from your Deployment&lt;/li&gt;
&lt;li&gt;Spreads the traffic across all Pods (this is called load balancing)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 – Scaling a Deployment (Making More Copies of Your App)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s now learn how to increase the number of app instances (called replicas) running in your cluster.&lt;/p&gt;

&lt;p&gt;First, check how many app instances (replicas) you currently have:&lt;br&gt;
&lt;code&gt;kubectl get deployments&lt;/code&gt;&lt;br&gt;
You should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsp4ds76ki0ik6amxaror.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsp4ds76ki0ik6amxaror.png" alt="check" width="800" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s what those columns in the screenshot above mean:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;NAME:&lt;/strong&gt; Name of your deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;READY:&lt;/strong&gt; How many Pods are currently running out of how many you want (e.g., 1/1).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UP-TO-DATE:&lt;/strong&gt; How many of those Pods are using the most recent version of your app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AVAILABLE:&lt;/strong&gt; How many Pods are ready and available to users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AGE:&lt;/strong&gt; How long the deployment has been running.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Want to see the ReplicaSet (the part of Kubernetes that manages Pods)?&lt;/strong&gt; run: &lt;code&gt;kubectl get rs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8hradm6nl593mqu4768q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8hradm6nl593mqu4768q.png" alt=" " width="800" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that the name of the ReplicaSet is always formatted as &lt;code&gt;[DEPLOYMENT-NAME]&lt;/code&gt;-&lt;code&gt;[RANDOM-STRING]&lt;/code&gt;. The random string is randomly generated and uses the pod-template-hash as a seed. As shown above &lt;code&gt;kubernetes-bootcamp-579cb4f987&lt;/code&gt;&lt;br&gt;
This shows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;DESIRED:&lt;/strong&gt; How many Pods you want.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CURRENT:&lt;/strong&gt; How many are actually running now.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Let’s scale up to 4 instances of the app.&lt;/strong&gt;&lt;br&gt;
let’s scale the Deployment to 4 replicas. We will use the kubectl scale command, following by the deployment type, name and desired number of instances: &lt;code&gt;kubectl scale deployments/kubernetes-bootcamp --replicas=4&lt;/code&gt;&lt;br&gt;
Note: This command tells Kubernetes:&lt;br&gt;
"Run 4 copies of this app instead of just 1."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcu0kimxg9s6bfih3isat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcu0kimxg9s6bfih3isat.png" alt="Run 4 copies" width="800" height="68"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confirm it worked:&lt;/strong&gt;&lt;br&gt;
Run this again: &lt;code&gt;kubectl get deployments&lt;/code&gt;&lt;br&gt;
You’ll now see: &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc1a0ijsphx5kk5jbll4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc1a0ijsphx5kk5jbll4.png" alt="kubectl get deployments" width="800" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The change was applied, and we have 4 instances of the application available. Next, let’s check if the number of Pods changed: &lt;code&gt;kubectl get pods -o wide&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkwxrn26kj4mp9t5rs6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkwxrn26kj4mp9t5rs6d.png" alt="4 different Pods" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above yuou should see 4 different Pods, each with its own IP address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want details about what happened behind the scenes?&lt;/strong&gt;&lt;br&gt;
You can inspect the deployment: &lt;code&gt;kubectl describe deployments/kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxukpif05rs2if9ev6p3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxukpif05rs2if9ev6p3.png" alt="system added" width="800" height="566"&gt;&lt;/a&gt;&lt;br&gt;
This shows events and confirms that the system added the new Pods successfully.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 – Load Balancing (Distributing Traffic Between Pods)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now let’s check if our Service is properly sharing traffic across all the app replicas (Pods).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Get the Service details&lt;/strong&gt;&lt;br&gt;
Run this to see the exposed IP and port of your app’s service: &lt;code&gt;kubectl describe services/kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcws90u09nk76avrxv1ug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcws90u09nk76avrxv1ug.png" alt="wait" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note for Docker Desktop users on macOS:&lt;/strong&gt;&lt;br&gt;
Because of network restrictions, your host can’t directly talk to the Pods.&lt;br&gt;
Run this instead to open a tunnel and launch your app in a browser: &lt;code&gt;minikube service kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcp0oqcxd17wpyq3nd2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcp0oqcxd17wpyq3nd2m.png" alt="tunneling" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This opens a window in your browser. Keep refreshing the page, each refresh will be served by a different Pod!&lt;br&gt;
You can stop the tunnel by pressing control + C in the terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Get the port that’s been exposed by the Service&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s create an environment variable so we don’t need to type the port each time: &lt;code&gt;export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')&lt;br&gt;
echo NODE_PORT=$NODE_PORT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fus9shks0eckpm0t2cmwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fus9shks0eckpm0t2cmwp.png" alt="open port" width="800" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Test the load balancer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now run this command several times: &lt;code&gt;curl $(minikube ip):$NODE_PORT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Each time you run it, you should see a response from a different Pod.&lt;br&gt;
That means Kubernetes is distributing (load-balancing) your requests across all running Pods.&lt;/p&gt;

&lt;p&gt;Step 3 - Scale Down&lt;br&gt;
To scale down the Service to 2 replicas, run again the scale command: &lt;code&gt;kubectl scale deployments/kubernetes-bootcamp --replicas=2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frev5ih5lbxd0bu4y76xt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frev5ih5lbxd0bu4y76xt.png" alt="replica=2" width="800" height="86"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;List the Deployments to check if the change was applied with the get deployments command: &lt;code&gt;kubectl get deployments&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrx7e2o54r5fbjthkza3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrx7e2o54r5fbjthkza3.png" alt="kubectl get deployments" width="800" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The number of replicas decreased to 2. List the number of Pods, with get pods: &lt;code&gt;kubectl get pods -o wide&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbesznbeh96kgcv2aa4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbesznbeh96kgcv2aa4l.png" alt="2 termitted" width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Shown above confirms that 2 Pods were terminated.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Module 6 – Updating Your Application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this section, you'll learn how to update an application that's already been deployed in Kubernetes. You'll use the kubectl set image command to apply the update and kubectl rollout undo to revert changes if necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 – Upgrading the Application Version&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Begin by checking the current deployments: &lt;code&gt;kubectl get deployments&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpuhhzd7753k0llehwe6n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpuhhzd7753k0llehwe6n.png" alt="get deployment" width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, verify which Pods are currently running: &lt;code&gt;kubectl get pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0fjiunq3mqoq5xpdrpqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0fjiunq3mqoq5xpdrpqn.png" alt="get pods" width="800" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To confirm the image version currently in use by the application, inspect the Pod details: &lt;code&gt;kubectl describe pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9h6a3e8d4u5zfffkau5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9h6a3e8d4u5zfffkau5w.png" alt="describe pods" width="800" height="906"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To update the image of the application to version 2, use the &lt;code&gt;set image&lt;/code&gt; command, followed by the deployment name and the new image version: &lt;code&gt;kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/k8s-minikube/kubernetes-bootcamp:v2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felrh85sqbvylqiacnn1u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felrh85sqbvylqiacnn1u.png" alt="deployment updated" width="800" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will trigger a rolling update, replacing the old Pods with new ones that use the new image. You can track the update by listing the Pods again: &lt;code&gt;kubectl get pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5twhfnwpi28vllr5x6uy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5twhfnwpi28vllr5x6uy.png" alt="kubectl get podsss" width="800" height="137"&gt;&lt;/a&gt;&lt;br&gt;
You’ll see the new Pods being created while the previous ones terminate.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 – Confirm the Application Has Been Updated&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To begin, ensure the application is still running correctly. First, determine the exposed IP and port by describing the service:&lt;br&gt;
&lt;code&gt;kubectl describe services/kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note for Docker Desktop users:&lt;/strong&gt; Since direct Pod access from the host is restricted, use this command to open a tunnel and access the app in your browser: minikube service kubernetes-bootcamp&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5130c4nrrlweu4b5u0tv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5130c4nrrlweu4b5u0tv.png" alt="browser" width="800" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can close the tunnel by pressing Control+C. Once done, proceed with the curl command shown below.&lt;/p&gt;

&lt;p&gt;Next, Create an environment variable called &lt;code&gt;NODE_PORT&lt;/code&gt; that has the value of the Node port assigned:: &lt;code&gt;export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')&lt;br&gt;
echo NODE_PORT=$NODE_PORT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpevuutg1yqwvx7kt0b4h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpevuutg1yqwvx7kt0b4h.png" alt="Nodeport" width="800" height="71"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, do a curl to the exposed IP and port, Now send a request to the application using the IP and Node port:&lt;br&gt;
&lt;code&gt;curl $(minikube ip):$NODE_PORT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Each time you run the command, you’ll likely hit a different Pod. Notice that all Pods are running the latest version (v2).&lt;/p&gt;

&lt;p&gt;You can also confirm the update by running the rollout status command: &lt;code&gt;kubectl rollout status deployments/kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6x5spcojip8ua3wzbtu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6x5spcojip8ua3wzbtu.png" alt="rollout status" width="800" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, confirm the image version by inspecting the Pod details:&lt;br&gt;
&lt;code&gt;kubectl describe pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmcxha2xel0tf4cqkud2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmcxha2xel0tf4cqkud2.png" alt="Image one" width="800" height="532"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rj7r3stnkmr6lgmk4v0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rj7r3stnkmr6lgmk4v0.png" alt="Image two" width="800" height="576"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwyjn2kkkrn80y5w5hjj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwyjn2kkkrn80y5w5hjj.png" alt="Image 3" width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check the Image field to ensure and notice it reflects version v2.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 - Rollback an update (Revert to a Previous AppVersion)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s simulate a failed deployment by attempting to update the app with a non-existent image version (v10): &lt;code&gt;kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/k8s-minikube/kubernetes-bootcamp:v10&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmnnm8w74sw1zqmsmvpx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmnnm8w74sw1zqmsmvpx.png" alt="kubernates" width="800" height="68"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check the deployment status: &lt;code&gt;kubectl get deloyments&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fj8lt3nc1l8d4wk8ns2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fj8lt3nc1l8d4wk8ns2.png" alt="get deployment" width="800" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that the output doesn’t list the desired number of available Pods. Run the get pods command to list all Pods: &lt;code&gt;kubectl get pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9xy2vhghxk317dim6dx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9xy2vhghxk317dim6dx.png" alt="get pods" width="800" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice some Pods are showing a status like &lt;code&gt;ImagePullBackOff&lt;/code&gt;, indicating that Kubernetes is unable to fetch the specified image.&lt;/p&gt;

&lt;p&gt;To understand what went wrong, use the following command to view Pod details: &lt;code&gt;kubectl describe pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuj4qitfleg584b3lnm3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuj4qitfleg584b3lnm3g.png" alt="Image A" width="800" height="717"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fff28yhjgaubp6qa4u7h0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fff28yhjgaubp6qa4u7h0.png" alt="Image B" width="800" height="719"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9e5cgub2s5tooef9t1um.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9e5cgub2s5tooef9t1um.png" alt="Image C" width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Events section, you’ll see errors confirming that the image tagged &lt;code&gt;v10&lt;/code&gt; couldn’t be found in the registry.&lt;/p&gt;

&lt;p&gt;To recover from this failed rollout, you can revert to the last stable version (v2) using: &lt;code&gt;kubectl rollout undo deployments/kubernetes-bootcamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command tells Kubernetes to roll the Deployment back to the most recent successful configuration.&lt;/p&gt;

&lt;p&gt;Now, verify that the Pods are back to normal: &lt;code&gt;kubectl get pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0o2qmylw8o7f63nbv35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0o2qmylw8o7f63nbv35.png" alt="kube get pods" width="800" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see the healthy Pods again. To confirm they’re using the correct image, run: &lt;code&gt;kubectl describe pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw33gy4qihhynb8g9ucb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw33gy4qihhynb8g9ucb.png" alt=" " width="800" height="711"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The deployment is once again using a stable version of the app (v2). Showing that the rollback was successful.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Kubernetes can seem complex at first, but starting with Minikube makes it much easier to learn and experiment. In this guide, we walked through how to deploy a simple application, explore how it runs in a pod, expose it to the outside world, scale it to handle more traffic, and update or roll back versions, all using real commands and step-by-step explanations.&lt;/p&gt;

&lt;p&gt;By the end of this article, you have built a solid foundation in how Kubernetes works behind the scenes. These are the same concepts used in real-world production environments just scaled up. The more you practice, the more confident you will become.&lt;/p&gt;

&lt;p&gt;Keep exploring, break things, fix them, and don’t be afraid to try more advanced features as you grow. Kubernetes is a powerful tool, and you’ve just taken the first important step.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>beginners</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Docker Made Simple: A Beginner’s Guide</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Fri, 04 Jul 2025 13:41:43 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/docker-made-simple-a-beginners-guide-2bem</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/docker-made-simple-a-beginners-guide-2bem</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;INTRODUCTION&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Docker is like a magic box that lets you run apps the same way everywhere whether on your Mac, a friend’s PC, or even in the cloud. No more "But it works on my machine!" problems.&lt;/p&gt;

&lt;p&gt;In this guide, we will cover eight parts in docker workshop which is &lt;br&gt;
PART 1: Containerize an application&lt;br&gt;
PART 2: Update the application&lt;br&gt;
PART 3: Share the application&lt;br&gt;
PART 4: Persist the DB&lt;br&gt;
PART 5: Use bind mounts&lt;br&gt;
PART 6: Multi container apps&lt;br&gt;
PART 7: Use Docker Compose&lt;br&gt;
PART 8: Image-building best practices&lt;/p&gt;

&lt;p&gt;So we will start from zero-no prior Docker knowledge! so at the end, you will know how to:&lt;br&gt;
✅ Package an app in a container (like a lunchbox).&lt;br&gt;
✅ Update it easily.&lt;br&gt;
✅ Share it with others.&lt;br&gt;
✅ Store data safely.&lt;br&gt;
✅ Run multiple apps together (like a mini internet café).&lt;br&gt;
✅ And much more show all with simple steps and Mac screenshots!&lt;/p&gt;

&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;PART 1: CONTAINERIZE AN APPLICATION (Put Your App in a Box)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;What’s a Container?&lt;br&gt;
Think of a container like a lunchbox:&lt;/p&gt;

&lt;p&gt;Your app is the sandwich.&lt;/p&gt;

&lt;p&gt;The Docker container is the lunchbox keeping it fresh.&lt;/p&gt;

&lt;p&gt;No matter where you open it (Mac, Windows, Linux), it works the same way!&lt;/p&gt;

&lt;p&gt;Before you begin you need to have make all this availiable in your PC&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have installed the latest version of Docker Desktop.&lt;/li&gt;
&lt;li&gt;You have installed a Git client.&lt;/li&gt;
&lt;li&gt;You have an IDE or a text editor to edit files. Docker recommends 
using Visual Studio Code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Steps&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Simple App (Let’s use Python)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Click on Terminal on the dropdwon click on new terminal &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwrp5axnygucpq6g66min.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwrp5axnygucpq6g66min.png" alt="Click on Terminal" width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and then create a directory and open the directory by runinig the command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir DevOpsstarter&lt;/code&gt;&lt;br&gt;
&lt;code&gt;cd DevOpsstarter&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtpwynu9pgdhb77mke1m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtpwynu9pgdhb77mke1m.png" alt="create a directory" width="800" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the app&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;a. Before you can run the application, you need to get the application source code onto your machine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the command: &lt;code&gt;git clone https://github.com/docker/getting-started-app.git&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32knk974ldpy5n3xzqdh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32knk974ldpy5n3xzqdh.png" alt="git clone" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;b. View the contents of the cloned repository. You should see the following files and sub-directories.&lt;/p&gt;

&lt;p&gt;getting-started-app/&lt;br&gt;
.dockerignore&lt;br&gt;
package.json&lt;br&gt;
README.md&lt;br&gt;
spec/&lt;br&gt;
src/&lt;br&gt;
yarn.lock&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6k5hlrqmoliftizbzaz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6k5hlrqmoliftizbzaz.png" alt="View the contents" width="800" height="227"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop0b2dfi5od6d00l8gzk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop0b2dfi5od6d00l8gzk.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the app's image
To create the image, you’ll need something called a Dockerfile. This is just a plain text file (it doesn’t even need a file extension) that lists step-by-step instructions. Docker reads these instructions to build a special kind of package called a container image, which is like a ready-to-use setup of your app or service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;a. In the "getting-started-app" folder, the same place where the package.json file is create a new file called Dockerfile &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb334jyhw0ac9cglezn2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb334jyhw0ac9cglezn2t.png" alt="getting-started-app" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then add the following content to it:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;# syntax=docker/dockerfile:1&lt;br&gt;
FROM node:lts-alpine&lt;br&gt;
WORKDIR /app&lt;br&gt;
COPY . .&lt;br&gt;
RUN yarn install --production&lt;br&gt;
CMD ["node", "src/index.js"]&lt;br&gt;
EXPOSE 3000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foca7e7rv7sgfxvd71x7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foca7e7rv7sgfxvd71x7s.png" alt="Dockerfile" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that this Dockerfile starts off with a node: lts-alpine base image, a small and efficient version of Linux that already has Node.js and Yarn (tools used to run and manage JavaScript apps) built in. Then, it copies your app’s files into this setup, installs everything the app needs, and starts it up.&lt;/p&gt;

&lt;p&gt;b. Build the image using the following commands:&lt;/p&gt;

&lt;p&gt;In the terminal, make sure you're in the getting-started-app directory. Replace /path/to/getting-started-app with the path to your getting-started-app directory.&lt;/p&gt;

&lt;p&gt;cd /path/to/getting-started-app&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwpl8ielutgrll8ubtceq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwpl8ielutgrll8ubtceq.png" alt="getting-started-app" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build the image.&lt;/p&gt;

&lt;p&gt;Run the command: &lt;code&gt;docker build -t getting-started .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgr06woa3wl3pnflkcwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgr06woa3wl3pnflkcwb.png" alt="docker build -t getting-started" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The docker build command uses your Dockerfile to create a new image of your app. You should have noticed that Docker downloaded a bunch of things, these things are called "layers." That happened because you told Docker to start with a base image called node:lts-alpine, but since it wasn’t already on your computer, Docker had to download it first.&lt;/p&gt;

&lt;p&gt;Once that was done, Docker followed the steps in your Dockerfile: it copied your app’s files into the image and used Yarn to install everything your app needs to run.&lt;/p&gt;

&lt;p&gt;The CMD part in the Dockerfile sets the default command that will run when you start a container using this image, so basically, it tells Docker how to launch your app.&lt;/p&gt;

&lt;p&gt;The -t flag in the command gives your image a name. In this case, you called it getting-started, so it’s easier to refer to later when you want to run it.&lt;/p&gt;

&lt;p&gt;Finally, the . (dot) at the end of the command just means: “look for the Dockerfile in this current folder.”&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start an app container&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that your image is ready, you can use the docker run command to start your app inside a container. Think of it like launching your app in its own little box.&lt;/p&gt;

&lt;p&gt;a. To run your app, use the &lt;em&gt;docker run&lt;/em&gt; command and tell it which image to use, so in this case, the one you just created (called getting-started). This starts your app inside a container.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run -d -p 127.0.0.1:3000:3000 getting-started&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsevaqyvabpqc3a1vt1b3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsevaqyvabpqc3a1vt1b3.png" alt="getting-started" width="800" height="48"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The -d flag (short for detach) tells Docker to run your app in the background. That means your app keeps running, but you get your terminal back and won’t see the app’s output (logs) unless you check them separately.&lt;/p&gt;

&lt;p&gt;The -p flag (short for publish) connects your app running inside Docker to your computer, so you can access it. It works like this:&lt;br&gt;
-p 127.0.0.1:3000:3000&lt;/p&gt;

&lt;p&gt;This means: take port 3000 from inside the container (where the app is running), and make it available on your computer at localhost:3000. Without this, you wouldn’t be able to open the app in your web browser.&lt;/p&gt;

&lt;p&gt;b. After waiting a few seconds, open your web browser and go to &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;. You should see your app up and running!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fncykvchnrwyr3nv3g7nh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fncykvchnrwyr3nv3g7nh.png" alt="localhost:3000" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add one or two items to your list and check that everything works like it should. You can mark items as done and also delete them. This means your front end (what you see) is successfully saving data to the back end (the storage part).&lt;/p&gt;

&lt;p&gt;Now, you have a working to-do list app with some items in it.&lt;/p&gt;

&lt;p&gt;If you want to see your running containers, you should notice at least one container using the getting-started image and running on port 3000. You can check this either by using commands in the terminal or by opening Docker Desktop, which has a user-friendly interface for managing containers.&lt;/p&gt;

&lt;p&gt;In CLI&lt;/p&gt;

&lt;p&gt;Run the &lt;code&gt;docker ps&lt;/code&gt; command in a terminal to list your containers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjphgq4yy3qwwb5jxlg2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjphgq4yy3qwwb5jxlg2b.png" alt="docker ps" width="800" height="43"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Docker Desktop&lt;br&gt;
select the Containers tab to see a list of your containers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F985p9fcgdxgnekt6cdtd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F985p9fcgdxgnekt6cdtd.png" alt="Docker Desktop" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this section, you learned how to create a Dockerfile to build an image. After building the image, you started a container and saw your app running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART 2: UPDATE THE APPLICATION (Change the Sandwich)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Why Update?&lt;br&gt;
You wouldn’t eat the same sandwich forever. Apps need updates too!&lt;/p&gt;

&lt;p&gt;In Part 1, you put a todo app into a Docker container (a process called containerizing). In this next part, you’ll learn how to update the app and its image. You’ll also see how to stop and delete a running container when you no longer need it.&lt;/p&gt;

&lt;p&gt;Update the source code&lt;br&gt;
In the following steps, you'll change the "empty text" when you don't have any todo list items to "You have no todo items yet! Add one above!"&lt;/p&gt;

&lt;p&gt;a. In the src/static/js/app.js file, update line 56 to use the new empty text.&lt;/p&gt;

&lt;p&gt;`- &lt;/p&gt;
&lt;p&gt;No items yet! Add one above!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You have no todo items yet! Add one above!&lt;/p&gt;`&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmmboxhixvivdtrad1c96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmmboxhixvivdtrad1c96.png" alt="No items yet" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl3i4mny887n5sfcdxd8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl3i4mny887n5sfcdxd8p.png" alt="You have no todo items yet" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;b. Build your updated version of the image, using the docker build command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker build -t getting-started .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykejjgrtgcu49x2f4xai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykejjgrtgcu49x2f4xai.png" alt="docker build -t getting-started ." width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;c. Start a new container using the updated code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run -dp 127.0.0.1:3000:3000 getting-started&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will saw an error like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker: Error response from daemon: driver failed programming external connectivity on endpoint laughing_burnell &lt;br&gt;
(bb242b2ca4d67eba76e79474fb36bb5125708ebdabd7f45c8eaf16caaabde9dd): Bind for 127.0.0.1:3000 failed: port is already allocated.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxhv2osmgkizp2bcn76b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxhv2osmgkizp2bcn76b.png" alt="Error response from daemon" width="800" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The error occurred because you aren't able to start the new container while your old container is still running. The reason is that the old container is already using the host's port 3000 and only one process on the machine (containers included) can listen to a specific port. To fix this, you need to remove the old container.&lt;/p&gt;

&lt;p&gt;Remove the old container&lt;/p&gt;

&lt;p&gt;To delete a container, you need to &lt;strong&gt;stop it first&lt;/strong&gt;. Once it’s no longer running, you can go ahead and remove it completely.&lt;br&gt;
You can do this using terminal commands or by using Docker Desktop’s easy-to-use interface, just pick whichever method you’re more comfortable with. But in this article we are using CLI command&lt;/p&gt;

&lt;p&gt;Remove a container using the CLI&lt;/p&gt;

&lt;p&gt;Get the ID of the container by using the &lt;em&gt;docker ps&lt;/em&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvbtmkaugsnmrnk3bjvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvbtmkaugsnmrnk3bjvf.png" alt="Get the ID" width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use the docker stop command to stop the container. Replace  with the ID from docker ps.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker stop &amp;lt;the-container-id&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfjzagheqsvhktz68qu2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfjzagheqsvhktz68qu2.png" alt="the-container-id" width="800" height="55"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the container has stopped, you can remove it by using the &lt;code&gt;docker rm&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2i57yfg7thvjvpoxmydj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2i57yfg7thvjvpoxmydj.png" alt="docker rm" width="800" height="45"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note&lt;br&gt;
You can stop and remove a container in a single command by adding the force flag to the docker rm command. For example: &lt;code&gt;docker rm -f &amp;lt;the-container-id&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start the updated app container&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, start your updated app using the docker run command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run -dp 127.0.0.1:3000:3000 getting-started&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Refresh your browser on &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; and you should see your updated help text.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Summary&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this section, you learned how to make changes to your app, rebuild the container to apply those updates, and how to stop and delete a container when you're done with it.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Part 3&lt;/strong&gt;
&lt;/h2&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;SHARE THE APPLICATION&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Once you have created a Docker image, you can share it with others. To do that, you need to upload it to a place called a Docker registry. The main one people use is called Docker Hub, it's where the images you've been using came from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker ID&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Docker ID lets you use Docker Hub, which is the biggest place to find and share container images. If you don’t have a Docker ID yet, you can create one for free via &lt;code&gt;https://app.docker.com/signup?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note, to push an image, you first have to create a respository on Docker Hub.&lt;/p&gt;

&lt;p&gt;a. Sign up or Sign in to Docker Hub via &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;https://hub.docker.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8mb8r4mpdijy0m7p5sv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8mb8r4mpdijy0m7p5sv.png" alt="https://hub.docker.com/" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;b. Click the &lt;strong&gt;"Create Repository"&lt;/strong&gt; button to start making a new space where you can store and share your Docker image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypouy1emcx25v4sm3mu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypouy1emcx25v4sm3mu6.png" alt="Create Repository" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;c. For the &lt;strong&gt;repository name&lt;/strong&gt;, type &lt;strong&gt;getting-started&lt;/strong&gt;.&lt;br&gt;
Also, make sure the &lt;strong&gt;Visibility&lt;/strong&gt; is set to &lt;strong&gt;Public&lt;/strong&gt;, so others can find and use your image. Then select create.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7lpcrvrfwwxokbsqxxc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7lpcrvrfwwxokbsqxxc.png" alt="repository name" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try to push an image to Docker Hub.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the command line, run the following commmand:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker push docker/getting-started&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn7nooajdc89qvj5im4wd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn7nooajdc89qvj5im4wd.png" alt="getting-started" width="800" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the above image you will see an error like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;docker push docker/getting-started&lt;br&gt;
The push refers to repository [docker.io/docker/getting-started]&lt;br&gt;
An image does not exist locally with the tag: docker/getting-started&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This error is normal because the image doesn’t have the right name yet. Docker is trying to find an image called &lt;strong&gt;docker/getting-started&lt;/strong&gt;, but the one you created is just named &lt;strong&gt;getting-started&lt;/strong&gt; on your computer.&lt;/p&gt;

&lt;p&gt;You can confirm this by running the command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker image ls&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2cnziqkbmj7g7324jl9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2cnziqkbmj7g7324jl9m.png" alt="docker image ls" width="800" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To fix the issue, start by signing in to Docker Hub with your Docker ID.
Use this command in your terminal: docker login YOUR-USER-NAME (replace YOUR-USER-NAME with your actual Docker username):&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0yzl1xa4hgnlni1u1kg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0yzl1xa4hgnlni1u1kg.png" alt="kosinachi" width="800" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the docker tag command to rename your getting-started image so it matches what Docker Hub expects.
Replace YOUR-USER-NAME with your actual Docker ID: &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker tag getting-started YOUR-USER-NAME/getting-started&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy09za525wr96w9dk4w2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy09za525wr96w9dk4w2.png" alt="YOUR-USER-NAME" width="800" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now run the docker push command again. If you're copying the value from Docker Hub, you can drop the tagname part, as you didn't add a tag to the image name. If you don't specify a tag, Docker uses a tag called latest.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker push YOUR-USER-NAME/getting-started&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tlfbriop0cbeoagdwvy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tlfbriop0cbeoagdwvy.png" alt="docker push" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run the image on a new instance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that your image is built and uploaded to a registry, you can test it on a fresh system that hasn’t used this image before.&lt;br&gt;
To do that, use &lt;strong&gt;Play with Docker&lt;/strong&gt;, a free online tool that lets you run Docker containers in a clean environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
Play with Docker runs on the amd64 platform. If you're using an ARM-based Mac with Apple silicon, your image may not work there unless it's rebuilt for amd64.&lt;/p&gt;

&lt;p&gt;To fix this, rebuild your Docker image using the --platform flag like this: &lt;code&gt;docker build --platform linux/amd64 -t YOUR-USER-NAME/getting-started .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxy83zhoc7sc2kbrs547.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxy83zhoc7sc2kbrs547.png" alt=" " width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your browser to Play with Docker via &lt;a href="https://labs.play-with-docker.com/" rel="noopener noreferrer"&gt;https://labs.play-with-docker.com/&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qqtzsfx6fji76o7lilf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qqtzsfx6fji76o7lilf.png" alt="lets play" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Login&lt;/strong&gt;, then choose &lt;strong&gt;docker&lt;/strong&gt; from the drop-down list to sign in with your Docker Hub account.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwvqxf4xhyq220k2iokw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwvqxf4xhyq220k2iokw.png" alt="Login" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sign in using your &lt;strong&gt;Docker Hub&lt;/strong&gt; account, then click &lt;strong&gt;Start&lt;/strong&gt; to launch your session on Play with Docker.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuo7ajaebn418ksrbmmoo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuo7ajaebn418ksrbmmoo.png" alt="Sign in using" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the &lt;strong&gt;ADD NEW INSTANCE&lt;/strong&gt; option on the left side bar. If you don't see it, make your browser a little wider. After a few seconds, a terminal window opens in your browser.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9s8njyooc6l23ixnlwlo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9s8njyooc6l23ixnlwlo.png" alt="ADD NEW INSTANCE" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft75uv9e0vapodum2g1lj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft75uv9e0vapodum2g1lj.png" alt="Added" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the terminal, run the following command to start your newly pushed app: &lt;code&gt;docker run -dp 0.0.0.0:3000:3000 YOUR-USER-NAME/getting-started&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should see Docker download (or "pull") the image from Docker Hub, and then start running it. After a few moments, your app should be up and ready to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt;&lt;br&gt;
You might have noticed that this time, the port is bound to &lt;strong&gt;0.0.0.0&lt;/strong&gt; instead of &lt;strong&gt;127.0.0.1&lt;/strong&gt; like before.&lt;/p&gt;

&lt;p&gt;Here's the difference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;127.0.0.1&lt;/strong&gt;: Only allows access from the same machine (localhost). The app is not reachable from outside.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0.0.0.0&lt;/strong&gt;: Makes the app available on &lt;strong&gt;all network interfaces&lt;/strong&gt;, so it can be accessed from other machines too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By using &lt;strong&gt;0.0.0.0&lt;/strong&gt;, you're allowing the container's port to be open to the outside world which is why it works in environments like Play with Docker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
In this section, you learned how to share your Docker images by pushing them to a registry like Docker Hub. Then, you tested it by running the image on a completely new instance just like in real-world scenarios.&lt;/p&gt;

&lt;p&gt;This is a common setup in &lt;strong&gt;CI (Continuous Integration) pipelines&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The pipeline builds and pushes a new image to a registry.&lt;/li&gt;
&lt;li&gt;Then, a production server or another environment pulls that image and runs it by always using the latest version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PART 4&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PERSIST THE DB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you noticed that your &lt;strong&gt;todo list is always empty&lt;/strong&gt; every time you start the container that’s expected. But why?&lt;/p&gt;

&lt;p&gt;This happens because &lt;strong&gt;containers don’t keep data by default&lt;/strong&gt;. When a container stops or is deleted, any data it stored is lost too. Each time you restart it, it's like a fresh install with no memory of the past.&lt;/p&gt;

&lt;p&gt;In the next part, you’ll explore &lt;strong&gt;how containers handle data&lt;/strong&gt; and how to &lt;strong&gt;persist&lt;/strong&gt; it across restarts using things like &lt;strong&gt;volumes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The container's filesystem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a container runs, it builds its filesystem from the &lt;strong&gt;layers in the image&lt;/strong&gt; it was created from. On top of that, Docker gives each container its own &lt;strong&gt;"scratch space"&lt;/strong&gt; — a writable layer where it can create, modify, or delete files.&lt;/p&gt;

&lt;p&gt;Here’s the key point:&lt;br&gt;
This scratch space is &lt;strong&gt;private to that container&lt;/strong&gt;. So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Any changes made (like adding a todo item) stay inside that container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Other containers&lt;/strong&gt; using the same image &lt;strong&gt;won’t see those changes&lt;/strong&gt;, because they get their own fresh scratch space.&lt;/li&gt;
&lt;li&gt;Once the container is deleted, its scratch space and all your data  is gone too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To share or persist data, you need a solution outside of the container’s temporary filesystem such as &lt;strong&gt;Docker volumes&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://dev.tourl"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Lets try It Out
&lt;/h3&gt;

&lt;p&gt;Let’s walk through an example to see how this actually works.&lt;/p&gt;

&lt;p&gt;To try this out, you'll run two separate containers. In the first one, you’ll create a file, and in the second one, you’ll check to see if that file is there.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start an Alpine container and create a new file in it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker run --rm alpine touch greeting.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6vwvc7fj3i17ha8yn26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6vwvc7fj3i17ha8yn26.png" alt="touch greeting.txt" width="800" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt;&lt;br&gt;
Any command you add after the image name (like &lt;strong&gt;alpine&lt;/strong&gt;) runs inside the container. For example, the command &lt;code&gt;touch greeting.txt&lt;/code&gt; creates a file named &lt;strong&gt;greeting.txt&lt;/strong&gt; in the container’s filesystem.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run a new Alpine container and use the stat command to see if the file is there:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker run --rm alpine stat greeting.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see a message like this, showing that the file isn’t there in the new container:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggg3jfxca6vqc091aau7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggg3jfxca6vqc091aau7.png" alt="docker" width="800" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;greeting.txt&lt;/strong&gt; file made in the first container wasn’t found in the second one. That’s because each container has its own separate writable layer. While both containers use the same base image layers, any changes (like new files) are stored in a layer that’s unique to each container and can’t be seen by others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Container volumes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Earlier, you saw that every time you run a container, it starts fresh based on the image. Any files the container creates or changes are lost when the container is deleted, and those changes are kept separate from everything else.&lt;/p&gt;

&lt;p&gt;Volumes help fix this.&lt;/p&gt;

&lt;p&gt;They let you connect a folder inside the container to your own computer. So if the container changes something in that folder, it also shows up on your machine — and it won’t be lost when the container stops or restarts.&lt;/p&gt;

&lt;p&gt;There are two main kinds of volumes. You’ll learn about both, but you’ll begin with something called a volume mount.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Persist the todo data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By default, the todo app saves its data in a file called todo.db, which is stored at /etc/todos/todo.db inside the container. This file uses something called SQLite, which is just a lightweight way to store data in one file. It’s great for small projects like this, even if it’s not ideal for big apps. Later on, you’ll learn how to use a more advanced database.&lt;/p&gt;

&lt;p&gt;Because all the data is in a single file, you can keep your data safe by saving that file outside the container — on your computer. That way, if the container stops or is deleted, the data stays.&lt;/p&gt;

&lt;p&gt;To do this, you will use something called a volume, which is like a storage box managed by Docker. You “attach” (or mount) it to the folder where the app saves its data. Then, even if the container goes away, the data in todo.db is saved and can be used again.&lt;/p&gt;

&lt;p&gt;You’re going to use a volume mount, which you can think of as a simple storage bucket. Docker takes care of where it’s stored you just need to know its name. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a volume and start the container&lt;/strong&gt;&lt;br&gt;
You can set up the volume and run the container either using the command line or Docker Desktop's visual interface. In this guide, we’ll use &lt;strong&gt;Docker Desktop’s graphical interface&lt;/strong&gt; to keep things simple and easy to follow.&lt;/p&gt;

&lt;p&gt;To create a volume&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select Volumes in Docker Desktop&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3ekmze3d7tpjdxj37fi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3ekmze3d7tpjdxj37fi.png" alt="Select Volumes" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Volumes, select Create.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0nq5gtwg3970cxd9iqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0nq5gtwg3970cxd9iqk.png" alt="Volumes, select Create" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Specify todo-db as the volume name, and then select Create.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ppphb5mrmrvw76ydad3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ppphb5mrmrvw76ydad3.png" alt="todo-db" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To stop and remove the app container:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Select Containers in Docker Desktop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select Delete in the Actions column for the container.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4lfbqfeoakyipso945as.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4lfbqfeoakyipso945as.png" alt="Select Delete" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To start the todo app container with the volume mounted:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on the search bar at the top of the Docker Desktop window.&lt;/li&gt;
&lt;li&gt;In the search window, select the Images tab.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxq2lmmq0hvu05sx7603.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxq2lmmq0hvu05sx7603.png" alt="search window" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the search box, specify the image name, getting-started&lt;/li&gt;
&lt;li&gt;Select your image and then select Run.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffeg175tzs5b9dvwe3nfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffeg175tzs5b9dvwe3nfe.png" alt="Select" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select Optional settings.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkfrlrlfp3nttqjjl54c.png" alt="Optional" width="800" height="497"&gt;
&lt;/li&gt;
&lt;li&gt;In Host port, specify the port, for example, 3000.&lt;/li&gt;
&lt;li&gt;In Host path, specify the name of the volume, todo-db.&lt;/li&gt;
&lt;li&gt;In Container path, specify /etc/todos.&lt;/li&gt;
&lt;li&gt;Select Run.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j44d42nq6zml7katf8u.png" alt="Container path" width="800" height="497"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwr0snmn9i6l3zujwls1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwr0snmn9i6l3zujwls1b.png" alt="path" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check to make sure the data is still there.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Shut down and delete the todo app container. You can do this using Docker Desktop or by running docker ps to find the container ID, then removing it with:
&lt;code&gt;docker rm -f &amp;lt;id&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9ggq8hmt7phqv9duu90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9ggq8hmt7phqv9duu90.png" alt="Shut down" width="800" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch a new container by repeating the steps you used earlier.&lt;/li&gt;
&lt;li&gt;Once you’re done reviewing your list, feel free to delete the container.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You’ve just learned how to save data so it’s not lost when the container stops.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explore what's inside the volume&lt;/strong&gt;&lt;br&gt;
Many people often wonder, “Where does Docker keep my data when I use a volume?” If you’re curious, you can find out by running the &lt;code&gt;docker volume inspect&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker volume inspect todo-db&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see output like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6oyslu8bh4myjo3nztzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6oyslu8bh4myjo3nztzp.png" alt="like the following" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Mountpoint&lt;/strong&gt; shows the exact place on your computer where the data is stored. Keep in mind that on most systems, you'll need &lt;strong&gt;admin or root access&lt;/strong&gt; to open this folder from your machine.&lt;/p&gt;

&lt;p&gt;Summary&lt;br&gt;
In this part, you discovered how to save container data so it remains available even after the container is stopped or removed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART 5&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;USE BIND MOUNTS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Part 4, you used something called a volume mount to save your app’s data, so it doesn’t get lost when the container stops. Volume mounts are great when you need a safe place to store your app’s files.&lt;/p&gt;

&lt;p&gt;Now you’ll learn about another type called a bind mount. This lets you share a folder from your computer directly with the container. So, if you're working on your app’s code and save a change, the container sees that change right away.&lt;/p&gt;

&lt;p&gt;This is super helpful while developing, because tools like nodemon (which we will use in this chapter) can watch your files and automatically restart the app whenever you make edits. Most programming languages have tools like this, and it makes testing and building apps much easier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick volume type comparisons&lt;/strong&gt;&lt;br&gt;
The following are examples of a named volume and a bind mount using --mount:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Named volume: type=volume,src=my-volume,target=/usr/local/data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhan33c3s1zv1mqsxipo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhan33c3s1zv1mqsxipo.png" alt="Named volume" width="800" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bind mount: type=bind,src=/path/to/data,target=/usr/local/data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8auqmg34ax9ouphiofwj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8auqmg34ax9ouphiofwj.png" alt="Bind mount" width="800" height="68"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following table outlines the main differences between volume mounts and bind mounts.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Volume Mount&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Bind Mount&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Managed by&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;td&gt;You (host OS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Location&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Inside Docker's storage&lt;/td&gt;
&lt;td&gt;Anywhere on your file system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Production data, persistent storage&lt;/td&gt;
&lt;td&gt;Development, local file access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Portability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (works across systems)&lt;/td&gt;
&lt;td&gt;Low (host-specific paths)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Docker backup tools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Not supported&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;Generally better&lt;/td&gt;
&lt;td&gt;Can be slower (especially on macOS)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you're developing an app, use bind mounts.&lt;br&gt;
If you're running production containers or need reliable data storage, use volumes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trying out bind mounts&lt;/strong&gt;&lt;br&gt;
Before we dive into using bind mounts for app development, let’s do a quick hands-on test. This simple experiment will help you see how bind mounts actually work in a real situation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make sure your &lt;strong&gt;getting-started-app&lt;/strong&gt; folder is located in a part of your computer that Docker Desktop is allowed to access. Docker has a setting that controls which folders on your machine can be shared with containers. If your folder isn’t in one of those approved locations, Docker won’t be able to use it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To find or change this setting, check Docker Desktop’s &lt;strong&gt;file sharing&lt;/strong&gt; options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmszilparakivs65fzbp2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmszilparakivs65fzbp2.png" alt="Docker Desktop" width="684" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;File Sharing&lt;/strong&gt; tab only shows up when Docker is running in &lt;strong&gt;Hyper-V mode&lt;/strong&gt;. That’s because in &lt;strong&gt;WSL 2 mode&lt;/strong&gt; and &lt;strong&gt;Windows container mode&lt;/strong&gt;, file sharing is handled automatically, so you don’t need to set it up manually.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a terminal and change directory to the getting-started-app directory.&lt;/li&gt;
&lt;li&gt;Run this command to start a terminal session inside an Ubuntu container, while also linking a folder from your computer (on Mac/Linux):
&lt;code&gt;docker run -it --mount type=bind,src="$(pwd)",target=/src ubuntu bash&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr7c1fuuyy79o209fz6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr7c1fuuyy79o209fz6a.png" alt="docker run" width="800" height="142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--mount type=bind&lt;/code&gt; option tells Docker to link a folder from your computer (in this case, your current working directory, like &lt;strong&gt;getting-started-app&lt;/strong&gt;) into the container. The &lt;code&gt;src&lt;/code&gt; is the folder on your computer, and the &lt;code&gt;target&lt;/code&gt; is the location inside the container where that folder will show up (here, &lt;strong&gt;/src&lt;/strong&gt;).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Once you run the command, Docker opens a bash terminal where you can type commands, starting in the main (root) folder of the container’s file system.
Then Run the command: pwd (This command displays the full path of the current working directory (the directory you're currently in).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftv65qbuzj9l6gie8yx2p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftv65qbuzj9l6gie8yx2p.png" alt="pwd" width="800" height="43"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the command ls (used to display the contents of a directory, including files and subdirectories)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc8uospvyiif3683krlxg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc8uospvyiif3683krlxg.png" alt="ls" width="800" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change directory to the src directory.
This is the folder you linked (mounted) when you started the container. If you list the files here, you will see the exact same files that are in your &lt;strong&gt;getting-started-app&lt;/strong&gt; folder on your computer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run the command: &lt;code&gt;cd src&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3d1io80h1r3lq2vq5lpl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3d1io80h1r3lq2vq5lpl.png" alt="src" width="800" height="62"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run this command &lt;code&gt;ls&lt;/code&gt; to list the item in that folder&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupls0yrcz6c9lmzen9mk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupls0yrcz6c9lmzen9mk.png" alt="Run this command" width="800" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new file named myfile.txt.
To create a new file myfile.txt, run the command: &lt;code&gt;touch myfile.txt&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2e1p6uuyp9wdz2i8p4yu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2e1p6uuyp9wdz2i8p4yu.png" alt="myfile.txt" width="800" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the command &lt;code&gt;ls&lt;/code&gt; to list the item in the file &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisfu3emm5qv0wa2hko90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisfu3emm5qv0wa2hko90.png" alt="ls1" width="800" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;getting-started-app&lt;/strong&gt; folder on your computer and you will see that the file &lt;strong&gt;myfile.txt&lt;/strong&gt; is inside it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnzmzby66ok1fb1jjba1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnzmzby66ok1fb1jjba1.png" alt="my file txt" width="680" height="726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On your computer, go to the &lt;strong&gt;getting-started-app&lt;/strong&gt; folder and delete the &lt;strong&gt;myfile.txt&lt;/strong&gt; file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozyovcf56tod4ewtizaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozyovcf56tod4ewtizaf.png" alt="delete myfile.txt" width="800" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the container, list the contents of the app directory once more. Observe that the file is now gone.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9c00cutlt1ruqfrdugp1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9c00cutlt1ruqfrdugp1.png" alt="In the container" width="800" height="49"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Exit the interactive container session by pressing &lt;strong&gt;Ctrl + D&lt;/strong&gt; on your keyboard.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s a quick overview of bind mounts! This showed how files can be shared between your computer and the container, and how any changes you make appear right away in both places. Now you’re ready to use bind mounts to help build and test your software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development containers&lt;/strong&gt;&lt;br&gt;
Using bind mounts is a popular way to develop locally because you don’t have to install all the build tools and software on your own computer. Instead, with just one &lt;code&gt;docker run&lt;/code&gt; command, Docker downloads everything your app needs, making it easier and faster to get started.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run your app in a development container&lt;/strong&gt;&lt;br&gt;
Here’s how to run a development container with a bind mount that will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mount your source code into the container&lt;/li&gt;
&lt;li&gt;Install all dependencies&lt;/li&gt;
&lt;li&gt;Start nodemon to watch for filesystem changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using Mac/linux&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From inside the &lt;strong&gt;getting-started-app&lt;/strong&gt; folder on your computer, run this command:
&lt;code&gt;docker run -dp 127.0.0.1:3000:3000 \
-w /app --mount type=bind,src="$(pwd)",target=/app \
node:18-alpine \
sh -c "yarn install &amp;amp;&amp;amp; yarn run dev"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg34603vfyu6bfg6w2im.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg34603vfyu6bfg6w2im.png" alt="getting-started-app" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s what each part of the command means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-d -p 127.0.0.1:3000:3000&lt;/code&gt; — Run the container in the background (detached mode) and connect port 3000 on your computer to port 3000 inside the container, but only accessible from your machine (localhost).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-w /app&lt;/code&gt; — Set the working directory inside the container to &lt;strong&gt;/app&lt;/strong&gt;, so commands run from there.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--mount type=bind,src="$(pwd)",target=/app&lt;/code&gt; — Link (bind mount) your current folder on your computer (&lt;code&gt;$(pwd)&lt;/code&gt;) into the container’s &lt;strong&gt;/app&lt;/strong&gt; folder.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;node:18-alpine&lt;/code&gt; — Use this lightweight Node.js image as the base for your container. This matches what your app uses in its Dockerfile.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sh -c "yarn install &amp;amp;&amp;amp; yarn run dev"&lt;/code&gt; — Run a shell command: first install the app’s dependencies with &lt;code&gt;yarn install&lt;/code&gt;, then start the development server with &lt;code&gt;yarn run dev&lt;/code&gt;. The dev script uses &lt;strong&gt;nodemon&lt;/strong&gt;, which watches for file changes and restarts the app automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, this command sets up your app inside the container, installs what it needs, and runs it so you can develop with live updates.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can check what’s happening by running &lt;code&gt;docker logs &amp;lt;container-id&amp;gt;&lt;/code&gt;. When you see this message, it means your app is up and running and ready to use:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63nak54qadsgdsnqgye4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63nak54qadsgdsnqgye4.png" alt="You can check" width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you’re finished checking the logs, press &lt;strong&gt;Ctrl + C&lt;/strong&gt; to stop and exit the log view.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Develop your app with the development container&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make changes to your app files on your computer, and you will see those updates happen instantly inside the running container.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the src/static/js/app.js file, on line 109, change the "Add Item" button to simply say "Add":&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;_- {submitting ? 'Adding...' : 'Add Item'}&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;{submitting ? 'Adding...' : 'Add'}_&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F580pzxml9r7xtii43c8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F580pzxml9r7xtii43c8g.png" alt="submitting" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Refresh your web browser, and you should see the update show up almost right away thanks to the bind mount. Nodemon notices the change and restarts the server automatically. It might take a few seconds for the server to restart, so if you see an error, just wait a moment and refresh again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqmlrbvls9k5jaumq7hx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqmlrbvls9k5jaumq7hx.png" alt="add" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and make any other changes you want. Every time you save a file, those updates will instantly show up inside the container thanks to the bind mount. Nodemon will spot the changes and automatically restart the app for you. When you’re finished, stop the container and create a new image by running:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker build -t getting-started .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now you can keep your database data saved and watch your app update live while you develop without having to rebuild the image every time.&lt;/p&gt;

&lt;p&gt;Besides volume mounts and bind mounts, Docker also offers other ways to connect storage and manage data for more advanced needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART 6&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;MULTI CONTAINER APPS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So far, we have been working with apps that run inside a single container. Now, we are going to add MySQL to your setup. A common question is: “Where should MySQL run? Should it be installed inside the same container, or run separately?”&lt;/p&gt;

&lt;p&gt;Usually, it’s best to have each container handle one job and do it well. Here are a few reasons why running MySQL in its own separate container is a good idea:&lt;br&gt;
Here’s a simpler way to explain those points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is possibility that we need to scale APIs and front-end separately from your database.&lt;/li&gt;
&lt;li&gt;Running MySQL in its own container lets you update or change its version without affecting the rest of your app.&lt;/li&gt;
&lt;li&gt;When working on your computer, you might run the database in a container, but in real production, you might use a managed database service instead — so you don’t want to include the database inside your app container.&lt;/li&gt;
&lt;li&gt;Containers are designed to run one main process. Running multiple processes (like your app and database together) means you’d need extra tools to manage them, which makes things more complicated when starting or stopping the container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Container networking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By default, containers run in their own isolated environments and don’t automatically know about other containers on the same machine.&lt;/p&gt;

&lt;p&gt;So, how can one container (like your app) talk to another (like a MySQL database)?&lt;/p&gt;

&lt;p&gt;The answer is: &lt;strong&gt;networking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you put both containers on the same Docker network, they can find and talk to each other just like they're on the same private network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start MySQL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can connect containers to a network in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Assign the network when you start the container&lt;/strong&gt; – This is the most common method. You specify the network as part of the &lt;code&gt;docker run&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Connect an already running container to a network&lt;/strong&gt; – If the container is already running, you can use &lt;code&gt;docker network connect&lt;/code&gt; to link it to a network afterward.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the next steps, we will first create a Docker network. Then, when we start the MySQL container, we will then attach it to that network right from the beginning so it can communicate with other containers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the network&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run the following command to create a new Docker network named todo-app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5q6no0emhvjk2t85c8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5q6no0emhvjk2t85c8k.png" alt="docker network" width="800" height="110"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start a MySQL container and connect it to the same network as your app. You’ll also set a few basic settings (like password and database name) so MySQL knows how to set itself up when it starts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run this command on MAC/LINUX/GITBASH&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run -d \&lt;br&gt;
    --network todo-app --network-alias mysql \&lt;br&gt;
    -v todo-mysql-data:/var/lib/mysql \&lt;br&gt;
    -e MYSQL_ROOT_PASSWORD=secret \&lt;br&gt;
    -e MYSQL_DATABASE=todos \&lt;br&gt;
    mysql:8.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nvsqf6kueo30p4p645n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nvsqf6kueo30p4p645n.png" alt="docker run" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the command you just saw, there’s a part called &lt;code&gt;--network-alias&lt;/code&gt;. Don’t worry about it for now — you’ll learn what it means and how it works a bit later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; In the command above, you might see a volume called &lt;code&gt;todo-mysql-data&lt;/code&gt; connected to &lt;code&gt;/var/lib/mysql&lt;/code&gt;, which is where MySQL saves its data. You didn’t manually create this volume with a command, Docker saw that you needed it and automatically made it for you.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To make sure your database is working, try connecting to it and check if the connection is successful.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker exec -it &amp;lt;mysql-container-id&amp;gt; mysql -u root -p&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpeqpu8eo4lyl9ry26ryb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpeqpu8eo4lyl9ry26ryb.png" alt="mysql container" width="800" height="39"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When asked for the password, type &lt;strong&gt;secret&lt;/strong&gt;. Once inside the MySQL command line, list the databases to make sure you see the one called &lt;strong&gt;todos&lt;/strong&gt;.&lt;br&gt;
mysql&amp;gt; &lt;code&gt;SHOW DATABASES;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc64ljeetogli0swwf7qe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc64ljeetogli0swwf7qe.png" alt="SHOW DATABASES" width="800" height="153"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Leave the MySQL command line by typing &lt;code&gt;exit&lt;/code&gt; so you go back to your regular terminal on your computer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxecms6dmlncbbfjhfee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxecms6dmlncbbfjhfee.png" alt="exit" width="800" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You now have a todos database set up and ready to be used in your app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect to MySQL&lt;/strong&gt;&lt;br&gt;
Now that MySQL is running, you might wonder how to connect to it from another container. Since each container has its own IP address, how do they find each other?&lt;/p&gt;

&lt;p&gt;To help answer this and learn more about how containers talk to each other, you’ll use a special container called &lt;strong&gt;nicolaka/netshoot&lt;/strong&gt;. It comes with handy tools to help you check and fix network problems between containers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start a new container using the &lt;strong&gt;nicolaka/netshoot&lt;/strong&gt; image and connect it to the same network as your other containers so it can communicate with them.
Run this command: &lt;code&gt;docker run -it --network todo-app nicolaka/netshoot&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8un2gkmwpwkaxntqsfg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8un2gkmwpwkaxntqsfg.png" alt=" " width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inside the container, we will run the &lt;code&gt;dig&lt;/code&gt; command, which helps look up addresses. So we will use it to find the IP address of the container named &lt;strong&gt;mysql&lt;/strong&gt;.
&lt;code&gt;dig mysql&lt;/code&gt;
You should get output like the following below.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yy1z0t2sb5ra88s4rex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yy1z0t2sb5ra88s4rex.png" alt="output like below" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the “ANSWER SECTION,” you’ll see that the name &lt;strong&gt;mysql&lt;/strong&gt; points to an IP address (like 172.20.0.2, though yours will probably be different). Normally, “mysql” isn’t a real website or address, but Docker knows how to match that name to the right container because of the network alias you set earlier.&lt;/p&gt;

&lt;p&gt;This means your app can just use the name &lt;strong&gt;mysql&lt;/strong&gt; to connect to the database, it doesn’t need to know the actual IP address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run your app with MySQL&lt;/strong&gt;&lt;br&gt;
The todo app lets you set a few simple settings to connect to MySQL by using environment variables. These are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MYSQL_HOST&lt;/strong&gt;: the name of the MySQL server to connect to&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MYSQL_USER&lt;/strong&gt;: the username for logging in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MYSQL_PASSWORD&lt;/strong&gt;: the password for that user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MYSQL_DB&lt;/strong&gt;: the specific database to use after connecting&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Using environment variables to set connection details is okay for testing and development, but it’s not recommended for apps running in real, live environments (production).&lt;/p&gt;

&lt;p&gt;A more secure way is to use &lt;strong&gt;secrets&lt;/strong&gt;, which many container tools support. These secrets are usually stored as files inside the container instead of just environment variables.&lt;/p&gt;

&lt;p&gt;Many apps, like MySQL and the todo app, let you use special environment variables ending with &lt;code&gt;_FILE&lt;/code&gt;. For example, if you set &lt;code&gt;MYSQL_PASSWORD_FILE&lt;/code&gt;, the app will read the password from a file instead of from a plain environment variable.&lt;/p&gt;

&lt;p&gt;Docker itself doesn’t manage this automatically — your app has to be programmed to check for these &lt;code&gt;_FILE&lt;/code&gt; variables and read the secret from the file.&lt;/p&gt;

&lt;p&gt;we’re now ready to start a container that’s set up for development.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up your container by providing all the environment variables from before (like MYSQL_HOST, MYSQL_USER, etc.) and connect it to your app’s network. Before running the command, make sure you’re inside the &lt;strong&gt;getting-started-app&lt;/strong&gt; folder on your computer.
Using MAC/LINUX&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker run -dp 127.0.0.1:3000:3000 \&lt;br&gt;
  -w /app -v "$(pwd):/app" \&lt;br&gt;
  --network todo-app \&lt;br&gt;
  -e MYSQL_HOST=mysql \&lt;br&gt;
  -e MYSQL_USER=root \&lt;br&gt;
  -e MYSQL_PASSWORD=secret \&lt;br&gt;
  -e MYSQL_DB=todos \&lt;br&gt;
  node:18-alpine \&lt;br&gt;
  sh -c "yarn install &amp;amp;&amp;amp; yarn run dev"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jagm26pu7jwdhj8izje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jagm26pu7jwdhj8izje.png" alt="yarn install" width="800" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you check the container’s logs using &lt;code&gt;docker logs -f &amp;lt;container-id&amp;gt;&lt;/code&gt;, you should see a message that shows it’s connected to and using the MySQL database. The message is seen below&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe51zx3kng2c4gyic895v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe51zx3kng2c4gyic895v.png" alt="mysql database" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the app in your web browser and add some tasks to your todo list.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmo7mdgexgu0z8a4nagum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmo7mdgexgu0z8a4nagum.png" alt="item" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bg4u0gxjl7i1ca1v9ig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bg4u0gxjl7i1ca1v9ig.png" alt="added item" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect to the MySQL database and check to make sure the items you added are saved there. Don’t forget, the password to log in is &lt;strong&gt;secret&lt;/strong&gt;.
&lt;code&gt;docker exec -it &amp;lt;mysql-container-id&amp;gt; mysql -p todos&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw1aixajbp30wgikv2jb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw1aixajbp30wgikv2jb.png" alt="docker exec" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’re in the MySQL command line, run this command:&lt;br&gt;
&lt;code&gt;select * from todo_items;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosr4gz00cpi1mwrtu522.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosr4gz00cpi1mwrtu522.png" alt="todo" width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now confirm the items we added earlier, so your table might look different because it has your own todo items, but you’ll be able to see that your tasks are saved there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now you have an app that saves its data in a separate database running in another container. You also learned how containers connect with each other over a network using DNS to find services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART 7&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;USE DOCKER COMPOSE&lt;/strong&gt;&lt;br&gt;
Docker Compose is a tool that makes it easy to set up and manage multiple containers for your app. You write a simple file (called a YAML file) that lists all the parts of your app, and then with just one command, you can start everything or stop it all.&lt;/p&gt;

&lt;p&gt;The best part is that this file lives in your project folder and gets saved with your code. This means anyone who wants to work on your project can just download it and start the app quickly using Compose. Lots of projects on places like GitHub or GitLab use this method now.&lt;/p&gt;

&lt;p&gt;CREATE THE COMPOSE FILE&lt;/p&gt;

&lt;p&gt;Inside the &lt;strong&gt;getting-started-app&lt;/strong&gt; folder, create a new file and name it &lt;strong&gt;compose.yaml&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuqqhhjvp2vwctvi152sp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuqqhhjvp2vwctvi152sp.png" alt="create folder" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;!compose yaml](&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/igxbgz07ua2vmqhzbyq0.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/igxbgz07ua2vmqhzbyq0.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;DEFINE THE APP SERVICE&lt;br&gt;
In part 6, you used the following command below to start the application service:&lt;br&gt;
&lt;code&gt;docker run -dp 127.0.0.1:3000:3000 \&lt;br&gt;
  -w /app -v "$(pwd):/app" \&lt;br&gt;
  --network todo-app \&lt;br&gt;
  -e MYSQL_HOST=mysql \&lt;br&gt;
  -e MYSQL_USER=root \&lt;br&gt;
  -e MYSQL_PASSWORD=secret \&lt;br&gt;
  -e MYSQL_DB=todos \&lt;br&gt;
  node:18-alpine \&lt;br&gt;
  sh -c "yarn install &amp;amp;&amp;amp; yarn run dev"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we are going to write the same setup inside the &lt;strong&gt;compose.yaml&lt;/strong&gt; file so Docker can use it automatically.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open compose.yaml in a text or code editor, and start by defining the name and image of the first service (or container) you want to run as part of your application. The name will automatically become a network alias, which will be useful when defining your MySQL service.
&lt;code&gt;services:
app:
image: node:18-alpine&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltiryijf6bfsnamiphj9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltiryijf6bfsnamiphj9.png" alt="node" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Usually, you'll find the &lt;code&gt;command&lt;/code&gt; line placed near the &lt;code&gt;image&lt;/code&gt; line in the &lt;strong&gt;compose.yaml&lt;/strong&gt; file, but it doesn't have to be in a specific order. Now, go ahead and add the &lt;code&gt;command&lt;/code&gt; section to your &lt;code&gt;compose.yaml&lt;/code&gt; file. This tells Docker what the container should do when it starts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;services:&lt;br&gt;
  app:&lt;br&gt;
    image: node:18-alpine&lt;br&gt;
    command: sh -c "yarn install &amp;amp;&amp;amp; yarn run dev"&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now take the part of the command that says -p 127.0.0.1:3000:3000 (which maps your computer’s port to the container’s port) and add it under the ports section of the service in your compose.yaml file. This lets you open the app in your browser at localhost:3000 just like before.
`services:
app:
image: node:18-alpine
command: sh -c "yarn install &amp;amp;&amp;amp; yarn run dev"
ports:

&lt;ul&gt;
&lt;li&gt;127.0.0.1:3000:3000`&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhkh2nyp69g1c5cyrxq5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhkh2nyp69g1c5cyrxq5o.png" alt="ports" width="800" height="350"&gt;&lt;/a&gt;&lt;br&gt;
This tells Docker to make the app available on your computer at port 3000.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now move the part of the command that sets the working directory (-w /app) and the part that connects your folder to the container (-v "$(pwd):/app"). In the compose.yaml file, this is done using working_dir and volumes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You don’t need to type the full path — Docker Compose lets you use relative paths (like .:/app, where . means “this folder”).&lt;/p&gt;

&lt;p&gt;Here’s how that looks in simple terms:&lt;br&gt;
&lt;code&gt;services:&lt;br&gt;
  app:&lt;br&gt;
    image: node:18-alpine&lt;br&gt;
    command: sh -c "yarn install &amp;amp;&amp;amp; yarn run dev"&lt;br&gt;
    ports:&lt;br&gt;
      - 127.0.0.1:3000:3000&lt;br&gt;
    working_dir: /app&lt;br&gt;
    volumes:&lt;br&gt;
      - ./:/app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrbsp07gmprluvrf9ll0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrbsp07gmprluvrf9ll0.png" alt="what it looks like" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lastly, move the environment variables (the ones you previously set with -e) into your compose.yaml file by using the environment section.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In simple terms, environment variables are like settings your app needs to connect to things like the database.&lt;/p&gt;

&lt;p&gt;Here’s how you add them:&lt;br&gt;
&lt;code&gt;services:&lt;br&gt;
  app:&lt;br&gt;
    image: node:18-alpine&lt;br&gt;
    command: sh -c "yarn install &amp;amp;&amp;amp; yarn run dev"&lt;br&gt;
    ports:&lt;br&gt;
      - 127.0.0.1:3000:3000&lt;br&gt;
    working_dir: /app&lt;br&gt;
    volumes:&lt;br&gt;
      - ./:/app&lt;br&gt;
    environment:&lt;br&gt;
      MYSQL_HOST: mysql&lt;br&gt;
      MYSQL_USER: root&lt;br&gt;
      MYSQL_PASSWORD: secret&lt;br&gt;
      MYSQL_DB: todos&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This setup tells the app how to connect to the database — using the host name mysql, a username, a password, and the database name. Now everything your app needs is inside the compose.yaml file.&lt;/p&gt;

&lt;p&gt;DEFINE THE MySQL SERVICE&lt;br&gt;
Now let’s set up the MySQL part of the app inside the compose.yaml file.&lt;/p&gt;

&lt;p&gt;Earlier, we started MySQL using a command like this below in the terminal:&lt;br&gt;
&lt;code&gt;docker run -d \&lt;br&gt;
  --network todo-app --network-alias mysql \&lt;br&gt;
  -v todo-mysql-data:/var/lib/mysql \&lt;br&gt;
  -e MYSQL_ROOT_PASSWORD=secret \&lt;br&gt;
  -e MYSQL_DATABASE=todos \&lt;br&gt;
  mysql:8.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjp82fx964owdk2s6812.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjp82fx964owdk2s6812.png" alt="mysql:8.0" width="800" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start by creating a new service in your &lt;code&gt;compose.yaml&lt;/code&gt; file called &lt;code&gt;mysql&lt;/code&gt;. This name will automatically act like a nickname (network alias) so other parts of your app can find it easily. Also, tell Docker which image to use for this service (in this case, the MySQL database image).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;services:&lt;br&gt;
  app:&lt;br&gt;
    # The app service definition&lt;br&gt;
  mysql:&lt;br&gt;
    image: mysql:8.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2158imnsrlyycovylxlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2158imnsrlyycovylxlh.png" alt="Mysql" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Next, set up the volume for the MySQL service. When you used &lt;code&gt;docker run&lt;/code&gt;, Docker made the volume for you automatically, but with Compose, you have to create it yourself. To do this, first list the volume at the top of your &lt;code&gt;compose.yaml&lt;/code&gt; file under a section called &lt;code&gt;volumes:&lt;/code&gt;. Then, in the MySQL service settings, tell it to use that volume by its name. Just giving the volume name is enough—Docker will use the usual settings.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;services:&lt;br&gt;
  app:&lt;br&gt;
    # The app service definition&lt;br&gt;
  mysql:&lt;br&gt;
    image: mysql:8.0&lt;br&gt;
    volumes:&lt;br&gt;
      - todo-mysql-data:/var/lib/mysql&lt;br&gt;
volumes:&lt;br&gt;
  todo-mysql-data:&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbws5oyv4rbyduym2wns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbws5oyv4rbyduym2wns.png" alt="todo-mysql-data:" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lastly, you need to add the environment variables. These are simple settings that tell the MySQL service important details like the username, password, and database name it should use.
`services:
app:
# The app service definition
mysql:
image: mysql:8.0
volumes:

&lt;ul&gt;
&lt;li&gt;todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:`&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxqs7of59dww1sk6t74j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxqs7of59dww1sk6t74j.png" alt="todo-mysql-data" width="800" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now, your full &lt;code&gt;compose.yaml&lt;/code&gt; file should look something like this:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;`services:&lt;br&gt;
  app:&lt;br&gt;
    image: node:18-alpine&lt;br&gt;
    command: sh -c "yarn install &amp;amp;&amp;amp; yarn run dev"&lt;br&gt;
    ports:&lt;br&gt;
      - 127.0.0.1:3000:3000&lt;br&gt;
    working_dir: /app&lt;br&gt;
    volumes:&lt;br&gt;
      - ./:/app&lt;br&gt;
    environment:&lt;br&gt;
      MYSQL_HOST: mysql&lt;br&gt;
      MYSQL_USER: root&lt;br&gt;
      MYSQL_PASSWORD: secret&lt;br&gt;
      MYSQL_DB: todos&lt;/p&gt;

&lt;p&gt;mysql:&lt;br&gt;
    image: mysql:8.0&lt;br&gt;
    volumes:&lt;br&gt;
      - todo-mysql-data:/var/lib/mysql&lt;br&gt;
    environment:&lt;br&gt;
      MYSQL_ROOT_PASSWORD: secret&lt;br&gt;
      MYSQL_DATABASE: todos&lt;/p&gt;

&lt;p&gt;volumes:&lt;br&gt;
  todo-mysql-data:`&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run the application stack&lt;/strong&gt;&lt;br&gt;
With our &lt;code&gt;compose.yaml&lt;/code&gt; file ready, we can now start your app easily.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Before starting, double-check that no other copies of the containers are running. You can use &lt;code&gt;docker ps&lt;/code&gt; to see running containers, and if you find any, use &lt;code&gt;docker rm -f &amp;lt;container-ids&amp;gt;&lt;/code&gt; to stop and remove them. As you can see below how we stop and removed two active containers that was running&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbm1h2jdtfqwktjfgjp0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbm1h2jdtfqwktjfgjp0i.png" alt=" " width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the command &lt;code&gt;docker compose up -d&lt;/code&gt; to start all parts of your app at once. The &lt;code&gt;-d&lt;/code&gt; flag makes everything run in the background so you can keep using your terminal. When you run the command you will see something like this below&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtp4rx9om1qsv30dftqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtp4rx9om1qsv30dftqp.png" alt="docker compose up" width="800" height="155"&gt;&lt;/a&gt;&lt;br&gt;
You’ll see that Docker Compose made a special storage space (called a volume) and a network for your app. It does this automatically to help the different parts of your app talk to each other, so you didn’t have to set it up yourself in the file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the logs by running &lt;code&gt;docker compose logs -f&lt;/code&gt;. This shows messages from all the parts of your app mixed together in one place. It’s really handy to see how things are working at the same time. The &lt;code&gt;-f&lt;/code&gt; means the logs keep updating live as new messages come in.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you already ran this command, you’ll see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmakotr62jqf5yte1an44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmakotr62jqf5yte1an44.png" alt="part 1" width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnct55l1nr4dcvp3wgs7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnct55l1nr4dcvp3wgs7.png" alt="part 2" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the start of each line in the logs, you’ll see the name of the service that created that message (it’s usually in color to make it easier to tell them apart).&lt;/p&gt;

&lt;p&gt;If you only want to see messages from one specific part of your app, just add the service name to the end of the command. For example:&lt;br&gt;
'docker compose logs -f app'&lt;br&gt;
This will only show logs from the app service.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now, you can open your web browser and go to &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;. Your app should be up and running there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcil09d03okd2hgql354n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcil09d03okd2hgql354n.png" alt="running there" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;See the app stack in Docker Desktop Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you open Docker Desktop, you’ll see a section called &lt;strong&gt;getting-started-app&lt;/strong&gt;. That’s just the name of your project, and it comes from the name of the folder where your &lt;code&gt;compose.yaml&lt;/code&gt; file is saved.&lt;/p&gt;

&lt;p&gt;When you click to expand it, you’ll see the two containers you set up — one for your app and one for MySQL. Their names are easy to understand because they follow a pattern like:&lt;br&gt;
&lt;strong&gt;[service-name]-[number]&lt;/strong&gt;&lt;br&gt;
For example, &lt;code&gt;app-1&lt;/code&gt; or &lt;code&gt;mysql-1&lt;/code&gt;. This helps you quickly know which one is which.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl7syu2t5q4lc9kfbbmp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl7syu2t5q4lc9kfbbmp.png" alt="app" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjc9tzkyhpwgcb9znjbz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjc9tzkyhpwgcb9znjbz.png" alt="sql" width="800" height="861"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TEAR IT ALL DOWN&lt;/strong&gt;&lt;br&gt;
When you're done and want to shut everything down, just run the command &lt;code&gt;docker compose down&lt;/code&gt;, or click the trash can icon in Docker Desktop next to your app. This will stop the containers and remove the network they were using.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Heads up:&lt;/strong&gt; When you use &lt;code&gt;docker compose down&lt;/code&gt;, it doesn't automatically delete the named volumes listed in your Compose file. These volumes hold your data, so they stick around unless you specifically tell Docker to remove them by adding the &lt;code&gt;--volumes&lt;/code&gt; option to the command.&lt;/p&gt;

&lt;p&gt;Also, if you're using Docker Desktop and delete your app from the dashboard, it won’t remove the volumes either. You’ll need to delete them manually if you want them gone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frxw1dt3s06ocs5hqs1sx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frxw1dt3s06ocs5hqs1sx.png" alt="docker compose down" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
In this part, you learned how &lt;strong&gt;Docker Compose&lt;/strong&gt; makes it easier to manage apps that use more than one container. Instead of running lots of commands, you can describe everything your app needs in one file, and then start or stop everything with just one simple command. This also makes it easier to share your app with others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART 8&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;IMAGE-BUILDING BEST PRACTICES&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Image layering&lt;/strong&gt;&lt;br&gt;
With the &lt;code&gt;docker image history&lt;/code&gt; command, you can look at the steps that were taken to build a Docker image—kind of like checking the recipe that was followed. Each line shows one layer that was added, along with the command that created it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the following command in your terminal to see the different layers that make up your getting-started image:
docker image history getting-started&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This will show you a list of steps (layers) that were used to build the image, including things like which base image was used, any files copied, packages installed, and other commands run during the build. It's like looking at the construction steps of the image, from bottom to top.&lt;br&gt;
You should get output that looks something like the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3vp18avcbkkcq4mh3xy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3vp18avcbkkcq4mh3xy.png" alt="should get" width="800" height="246"&gt;&lt;/a&gt;&lt;br&gt;
Each line you see is like a step in a recipe. The line at the bottom shows the base image (the starting point), and each line above it shows something that was added later. This view helps you understand how the image was built and lets you spot which parts take up the most space—so if your image is too big, you can figure out why.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You might see that some of the lines are cut short (truncated). If you want to see the whole thing without anything being cut off, you can add &lt;code&gt;--no-trunc&lt;/code&gt; to the command. That way, all the details will be shown in full.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker image history --no-trunc getting-started&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscjywao8ny7oertc7xqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscjywao8ny7oertc7xqt.png" alt="no-trunc" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer caching&lt;/strong&gt;&lt;br&gt;
Now that you’ve seen how the image layers work, here’s an important tip to make your builds faster: if one layer changes, everything built after it has to be rebuilt too.&lt;/p&gt;

&lt;p&gt;Check out this Dockerfile you made for the getting started app to see how this happens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6pbmfu4ifzrbnxhybcv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6pbmfu4ifzrbnxhybcv.png" alt="Check out this Dockerfile" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s go back to what the image history showed: every line in your Dockerfile becomes a separate layer in the image. You might’ve noticed that when you made a small change, like updating your app, Docker reinstalled all your packages again—even though they didn’t change. That’s a waste of time and effort.&lt;/p&gt;

&lt;p&gt;Here’s how to fix it: rearrange your Dockerfile so Docker installs your dependencies &lt;em&gt;before&lt;/em&gt; it copies the rest of your app code. For Node.js apps, this means:&lt;/p&gt;

&lt;p&gt;a. First, copy in just the &lt;code&gt;package.json&lt;/code&gt; file.&lt;br&gt;
b. Then install the dependencies.&lt;br&gt;
c. Finally, copy in the rest of the app.&lt;/p&gt;

&lt;p&gt;By doing this, Docker will only reinstall packages if &lt;code&gt;package.json&lt;/code&gt; changes, saving time during rebuilds.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the Dockerfile so that it first brings in the file that lists your app’s tools (&lt;code&gt;package.json&lt;/code&gt;), installs those tools, and &lt;strong&gt;then&lt;/strong&gt; adds the rest of your project files. This way, Docker won’t reinstall everything every time you make a small change to your code—it’ll only do that if the list of tools changes.
&lt;code&gt;# syntax=docker/dockerfile:1
FROM node:lts-alpine
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --production
COPY . .
CMD ["node", "src/index.js"]&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkufdyz4d3m9n3uo2hi3t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkufdyz4d3m9n3uo2hi3t.png" alt="update" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a fresh version of your app’s image by running the &lt;code&gt;docker build&lt;/code&gt; command. This tells Docker to put everything together based on your updated instructions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker build -t getting-started .&lt;/code&gt;&lt;br&gt;
You should see output like the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkt2ksl2aahw07va63yug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkt2ksl2aahw07va63yug.png" alt="building docker" width="800" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;code&gt;src/static/index.html&lt;/code&gt; file and change the title of the page. For example, change it from whatever it is now to say: &lt;strong&gt;"The Awesome Todo App"&lt;/strong&gt;. This is just a small update to see your changes in action.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumbgp8lakdje8bt8vt6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumbgp8lakdje8bt8vt6f.png" alt="src/static/index.html" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now run the command to build your Docker image again:
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker build -t getting-started .&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;This time, the build process should be faster for some steps. That’s because Docker notices that some things didn’t change (like the dependencies), so it reuses them instead of redoing everything from scratch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0td8i349913dd7rgrcmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0td8i349913dd7rgrcmc.png" alt="docker changes" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-stage builds&lt;/strong&gt;&lt;br&gt;
Multi-stage builds are a smart way to break your image creation into steps. Here's what that means in simple terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You use one part to build the app&lt;/strong&gt;, where you might need tools and libraries just to help create the final version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Then, you create a second, much smaller part&lt;/strong&gt;, where you only keep what the app needs to run, not all the extra tools used during building.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach helps you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep things clean&lt;/strong&gt; by not mixing build tools with your actual app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make your final image smaller&lt;/strong&gt;, faster, and easier to share or deploy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Maven/Tomcat example&lt;/strong&gt;&lt;br&gt;
When you're building Java apps, you need some heavy tools like the &lt;strong&gt;JDK (Java Development Kit)&lt;/strong&gt; and build tools like &lt;strong&gt;Maven or Gradle&lt;/strong&gt; to put your code together. But once your app is built, &lt;strong&gt;you don’t need those tools anymore&lt;/strong&gt; to actually run the app.&lt;/p&gt;

&lt;p&gt;So instead of putting everything into one image (which makes it big and messy), &lt;strong&gt;multi-stage builds let you use those tools only while building&lt;/strong&gt;, and then &lt;strong&gt;leave them out of the final product&lt;/strong&gt;. This way, your final app image is &lt;strong&gt;lighter, faster, and cleaner&lt;/strong&gt; — it only contains what’s truly needed to run the app.&lt;/p&gt;

&lt;h1&gt;
  
  
  syntax=docker/dockerfile:1
&lt;/h1&gt;

&lt;p&gt;FROM maven AS build&lt;br&gt;
WORKDIR /app&lt;br&gt;
COPY . .&lt;br&gt;
RUN mvn package&lt;/p&gt;

&lt;p&gt;FROM tomcat&lt;br&gt;
COPY --from=build /app/target/file.war /usr/local/tomcat/webapps &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbs9n3j39mdw1503afmxb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbs9n3j39mdw1503afmxb.png" alt="Maven/Tomcat" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In simple terms: this setup has &lt;strong&gt;two steps&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;first step&lt;/strong&gt; (called &lt;em&gt;build&lt;/em&gt;) uses Maven to put your Java app together.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;second step&lt;/strong&gt; (starting with &lt;code&gt;FROM tomcat&lt;/code&gt;) is where you &lt;strong&gt;take the finished app&lt;/strong&gt; from the first step and place it into a clean, ready-to-run environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only the &lt;strong&gt;second step&lt;/strong&gt; ends up in the final Docker image, so the extra tools used during the build (like Maven) &lt;strong&gt;aren’t included&lt;/strong&gt; in the final product. This keeps the image &lt;strong&gt;small and tidy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If needed, you can also choose to stop after a certain step using the &lt;code&gt;--target&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React example&lt;/strong&gt;&lt;br&gt;
When you build a React app, you need Node.js to turn your code (like JSX and SASS) into regular files like HTML, JavaScript, and CSS that browsers can understand. This is called compiling.&lt;/p&gt;

&lt;p&gt;But once that’s done, for running the app in production, you don’t need Node.js anymore. Instead, you can just serve those ready-made files using a simple web server like nginx inside a lightweight container. This keeps things faster and simpler.&lt;br&gt;
`# syntax=docker/dockerfile:1&lt;br&gt;
FROM node:lts AS build&lt;br&gt;
WORKDIR /app&lt;br&gt;
COPY package* yarn.lock ./&lt;br&gt;
RUN yarn install&lt;br&gt;
COPY public ./public&lt;br&gt;
COPY src ./src&lt;br&gt;
RUN yarn run build&lt;/p&gt;

&lt;p&gt;FROM nginx:alpine&lt;br&gt;
COPY --from=build /app/build /usr/share/nginx/html`&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6f9latfrvfhf8sw7hr4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6f9latfrvfhf8sw7hr4m.png" alt="FROM nginx:alpine" width="800" height="413"&gt;&lt;/a&gt;&lt;br&gt;
In the earlier example, the Dockerfile first uses a node image to build the app (which helps speed things up by reusing parts it already made), then it takes the finished files and puts them into a simple nginx web server container to run the app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this part, you learned some good tips for building images, like saving work with layer caching and using multi-step builds to make smaller, cleaner images.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>beginners</category>
      <category>programming</category>
      <category>cloud</category>
    </item>
    <item>
      <title>How to Create and Configure a Virtual Network in Azure (The Easy Way via Azure Portal)</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Tue, 29 Apr 2025 12:17:53 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/how-to-create-and-configure-a-virtual-network-in-azure-the-easy-way-via-azure-portal-4nd</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/how-to-create-and-configure-a-virtual-network-in-azure-the-easy-way-via-azure-portal-4nd</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you're just getting started with Microsoft Azure, there's one foundational concept you will run into early: &lt;strong&gt;Virtual Networks&lt;/strong&gt;, or VNets.&lt;/p&gt;

&lt;p&gt;Think of a VNet as your own private network in the cloud — a space where your resources (like virtual machines, databases, and web apps) can securely talk to each other. In this guide, i will walk through how to create and configure one using the &lt;strong&gt;Azure Portal&lt;/strong&gt;, no command-line knowledge required.&lt;/p&gt;

&lt;p&gt;Let’s dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Why Virtual Networks Matter
&lt;/h2&gt;

&lt;p&gt;When you spin up resources in Azure, you don’t want them floating around the internet without guardrails. A VNet gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isolation and segmentation&lt;/strong&gt; of services&lt;/li&gt;
&lt;li&gt;Control over &lt;strong&gt;IP address ranges&lt;/strong&gt;, &lt;strong&gt;subnets&lt;/strong&gt;, and &lt;strong&gt;routing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Integration with &lt;strong&gt;on-premises networks&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The ability to set &lt;strong&gt;firewall rules&lt;/strong&gt; using Network Security Groups (NSGs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, if you're building anything beyond a demo app, you will likely need a VNet.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ What You will Need
&lt;/h2&gt;

&lt;p&gt;Before we get started, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://azure.microsoft.com/en-us/free/" rel="noopener noreferrer"&gt;Microsoft Azure account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Access to the &lt;a href="https://portal.azure.com" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🚧 Step 1: Create a Virtual Network
&lt;/h2&gt;

&lt;p&gt;Let’s start by creating the VNet itself.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Log in to the Azure Portal&lt;/strong&gt;
Head over to &lt;a href="https://portal.azure.com" rel="noopener noreferrer"&gt;https://portal.azure.com&lt;/a&gt; and sign in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiag5b6hsuewmmmt37oga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiag5b6hsuewmmmt37oga.png" alt="Log in to the Azure Portal" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search for “Virtual Networks”&lt;/strong&gt;
Use the search bar at the top of the portal, type &lt;code&gt;Virtual Networks&lt;/code&gt;, and select the service from the dropdown.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbzk3rug3sk4gotpzuuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbzk3rug3sk4gotpzuuw.png" alt="Virtual Networks" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Click “+ Create” to Start a New VNet&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0d4e6ta4frfftftba0l4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0d4e6ta4frfftftba0l4.png" alt="Create" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fill in the Basics&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscription&lt;/strong&gt;: Choose the correct subscription&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Group&lt;/strong&gt;: Create a new one (e.g., &lt;code&gt;VNet-Demo-RG&lt;/code&gt;) and press ok or use an existing resource group&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febib9pelgj6j1ytnbycu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febib9pelgj6j1ytnbycu.png" alt="Resource Group" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: Something like &lt;code&gt;MyFirstVNet&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Region&lt;/strong&gt;: Pick the region closest to you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs00nhbuxwcv46cauvn4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs00nhbuxwcv46cauvn4i.png" alt="MyFirstVNet" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set the IP Address Space&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on IP addresses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07ogd7o1899c2vjkxo1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07ogd7o1899c2vjkxo1j.png" alt="IP addresses" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The default should be something like &lt;code&gt;10.0.0.0/16&lt;/code&gt;, which is fine for now&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F404stah23jvnx5c6n5ry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F404stah23jvnx5c6n5ry.png" alt="default should be something" width="800" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add your first &lt;strong&gt;subnet&lt;/strong&gt;, e.g., &lt;code&gt;Frontend&lt;/code&gt; with address range &lt;code&gt;10.0.0.0/24&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click on the pensil sign on default &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38m4u7cmlw0t71iq89zb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38m4u7cmlw0t71iq89zb.png" alt="Image pensil sign" width="800" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;change the name to Frontend. Explore the other default settings including the starting address, size and subnet address range and click on Save&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt61f52bwrq439zccu54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt61f52bwrq439zccu54.png" alt="save" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add your second &lt;strong&gt;subnet&lt;/strong&gt;, e.g., &lt;code&gt;Backend&lt;/code&gt; with address range &lt;code&gt;10.0.0.0/24&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the +Add a Subnet&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fviwusgmsik2ihfbfvdcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fviwusgmsik2ihfbfvdcp.png" alt="+Add a Subnet" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change the name to Backend. Explore the default settings and click on Add&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwxq047mxymbdq57bxj4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwxq047mxymbdq57bxj4v.png" alt="Backend" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6bh5a2ni4ic61wobbqjb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6bh5a2ni4ic61wobbqjb.png" alt="Full screen" width="800" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Click through the Remaining Tabs&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
For now, you can skip advanced features like security and DNS unless you're familiar with them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Click “Review + Create”&lt;/strong&gt;, then &lt;strong&gt;Create&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fif8wwss8sx9fsvn8jh6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fif8wwss8sx9fsvn8jh6f.png" alt="review and create" width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe75lz9kv76qubane5q38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe75lz9kv76qubane5q38.png" alt="validation to finish" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployment is complete&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F367tuate9lmax31h2pxh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F367tuate9lmax31h2pxh.png" alt="Deployment complete" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Step 2: Configure the VNet to use firewall
&lt;/h2&gt;

&lt;p&gt;Now that your network exists, let’s do a little customization.&lt;/p&gt;

&lt;h3&gt;
  
  
  +Add More Subnets
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a new Virtual Network: Go to the search box and type virtual network, on the dropdwon click on virtual network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cs0ua2586s9ximr01es.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cs0ua2586s9ximr01es.png" alt="Virtual Network" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on +Create&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgspfm8tkjfgnywzz0fl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgspfm8tkjfgnywzz0fl.png" alt="Create" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use your active subcription, select&lt;/li&gt;
&lt;li&gt;Resource group &lt;/li&gt;
&lt;li&gt;Choose a name, and a region (prefferable same with the previous region used)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p2rb2wwhefykkebammr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p2rb2wwhefykkebammr.png" alt="Resource group" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on IP addresses &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgperskohxh245geyi0l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgperskohxh245geyi0l.png" alt="IP addresses" width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on default&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8prn8lhfwg04832svi1k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8prn8lhfwg04832svi1k.png" alt="defaukt" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the subnet purpose, click on the dropdown and click on Azure Firewall&lt;/li&gt;
&lt;li&gt;Then click on save&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa94ets5utz3kblg3f092.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa94ets5utz3kblg3f092.png" alt="click" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Click “Review + Create”&lt;/strong&gt;, then &lt;strong&gt;Create&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nb853iwqpad9tt3el5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nb853iwqpad9tt3el5u.png" alt="Review + Create" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihcfwd0jux4runstmb9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihcfwd0jux4runstmb9w.png" alt="Create" width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up VNet Peering
&lt;/h2&gt;

&lt;p&gt;If you're working across multiple VNets (e.g., for isolation or region-based separation), &lt;strong&gt;peering&lt;/strong&gt; connects them securely.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Just go to the &lt;strong&gt;Peerings&lt;/strong&gt; section of your MyFirstVNet settings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;+Add&lt;/strong&gt;, and set up a peer with another VNet in your subscription.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2so0u3lwj1zc7y0r1x8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2so0u3lwj1zc7y0r1x8j.png" alt="peer" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the remote virual network , peering link name should be MyFirstVbet-to-hub&lt;/li&gt;
&lt;li&gt;On the virtual Network choose hub-vnet&lt;/li&gt;
&lt;li&gt;Check the resource manager and also check the Allow 'hub-vnet to access MyFirstVNet'&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu1qvft48mhblh837ka8y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu1qvft48mhblh837ka8y.png" alt="MyFirstVNet" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the local virual network , peering link name should be hub-to-MyFirstVNet&lt;/li&gt;
&lt;li&gt;Check the resource manager and also check the Allow 'MyFirstVNet to access hub-vnet'&lt;/li&gt;
&lt;li&gt;Then click on Add&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr50tq9cy2118kcp6hupu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr50tq9cy2118kcp6hupu.png" alt="MyFirstVNet" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To confirm the peering of the remote VNet and Local VNet was successfull, the peering state of the two VNet will show connected&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mnroj4jnl142j2mk8iw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mnroj4jnl142j2mk8iw.png" alt="VNet" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🧭 Where to Go From Here
&lt;/h2&gt;

&lt;p&gt;Now that your VNet is in place, here are a few things you might want to explore next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy a &lt;strong&gt;Virtual Machine&lt;/strong&gt; into one of your subnets&lt;/li&gt;
&lt;li&gt;Experiment with &lt;strong&gt;NSG rules&lt;/strong&gt; to control traffic&lt;/li&gt;
&lt;li&gt;Try &lt;strong&gt;connecting two VNets&lt;/strong&gt; using peering&lt;/li&gt;
&lt;li&gt;Set up a &lt;strong&gt;VPN Gateway&lt;/strong&gt; to connect your VNet to an on-prem network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔄 A Quick Word on VNet Peering&lt;br&gt;
In the steps we went through, I mentioned something called Virtual Network Peering, but what does that actually mean?&lt;/p&gt;

&lt;p&gt;Think of each Virtual Network (VNet) in Azure like a private neighborhood. By default, one neighborhood can’t talk to another even if you own both. VNet Peering is like building a secure road between two of your own neighborhoods, so that resources (like virtual machines or apps) in one can easily and privately communicate with those in the other.&lt;/p&gt;

&lt;p&gt;It’s super useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You want to organize resources into separate VNets (maybe for security or scaling reasons)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have VNets in different regions but need them to work together&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You’re building a hub-and-spoke network model&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the best part? The traffic between VNets stays private, it doesn’t go over the public internet.&lt;/p&gt;

&lt;p&gt;So when you add a peering connection in Azure, you’re basically telling two of your networks, “Hey, you’re family now go ahead and talk to each other securely.”&lt;/p&gt;

&lt;h2&gt;
  
  
  💬 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Getting hands-on with Azure networking doesn’t have to be intimidating. The Azure Portal makes it surprisingly straightforward to set up and customize a Virtual Network.&lt;/p&gt;

&lt;p&gt;If this was helpful or if you want a follow-up guide on &lt;strong&gt;deploying VMs&lt;/strong&gt; or &lt;strong&gt;setting up hybrid networks&lt;/strong&gt;, let me know in the comments. Happy building!&lt;/p&gt;

&lt;p&gt;🧵 &lt;em&gt;Follow me for more beginner-friendly Azure and cloud development tutorials!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>azure</category>
      <category>networking</category>
      <category>network</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Introduction to Creating Web and Console Applications with C#</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Fri, 21 Mar 2025 13:32:35 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/introduction-to-creating-web-and-console-applications-with-c-506j</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/introduction-to-creating-web-and-console-applications-with-c-506j</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;C# is a versatile programming language used for various applications, including console and web applications. In this guide, we will walk through setting up Visual Studio Code (VS Code) for C# development and creating two simple applications: a console application and a web application.&lt;/p&gt;

&lt;p&gt;A console application is a program that runs in a command-line interface (CLI) or terminal, allowing user interaction via text input and output.  Console applications are commonly used for automation, testing, and simple utilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Requirements&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before starting, ensure you have the following installed on your system:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Visual Studio Code (VS Code) - Download and install it from &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;https://code.visualstudio.com/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.NET SDK - Download and install the latest .NET SDK from &lt;a href="https://dotnet.microsoft.com/download" rel="noopener noreferrer"&gt;https://dotnet.microsoft.com/download&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch7x6pszr6favh9iqbpq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch7x6pszr6favh9iqbpq.png" alt="NET SDK" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;C# Extension for VS Code - Install it via the VS Code Extensions Marketplace&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Setting Up VS Code for C#&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Install VS Code and Required Extensions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open VS Code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to the Extensions Marketplace (Ctrl + Shift + X).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Search for "C# Dev Kit" and install the official C# extension by Microsoft.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq53cgge49mlliam7o9re.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq53cgge49mlliam7o9re.png" alt="C# Dev Kit" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify .NET Installation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;On the upper left, click on view, on the dropdown click on terminal to Open a terminal in VS Code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the command: dotnet --version&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdoxug5o6uraxlfppmc4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdoxug5o6uraxlfppmc4g.png" alt="Image description" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If .NET is installed correctly, it outputs version number will show&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Creating a Simple C# Web App with ASP.NET Core&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Create a New web Project&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a directory by opening a terminal in VS Code and run: &lt;strong&gt;mkdir (directory/folder name)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspm4r0hv1v16v4frcse7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspm4r0hv1v16v4frcse7.png" alt="directory name" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;open the directory by running the command: &lt;strong&gt;cd (directory/folder name)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmdg1m9cvip1lmj8g5my.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmdg1m9cvip1lmj8g5my.png" alt="directory" width="800" height="35"&gt;&lt;/a&gt;&lt;br&gt;
we have successfully created and opened a directory/folder &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To create a new web application, give it a name put it inside new directory/folder, run the command: &lt;strong&gt;dotnet new web -n Mywebapp -o .&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsbcp3x9dyibvsjcjon8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsbcp3x9dyibvsjcjon8.png" alt="run the command" width="800" height="169"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Breakdown of Flags:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dotnet new web&lt;/strong&gt; → Creates a new ASP.NET Core web project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;-n Mywebapp&lt;/strong&gt; → Specifies the name of the project (Mywebapp).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;-o (or --output)&lt;/strong&gt; → Specifies the output directory for the project files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the left side click on &lt;strong&gt;mywebapp&lt;/strong&gt; on the dropdown click on &lt;strong&gt;program.cs&lt;/strong&gt;
Notice that this command has created a simple application for us called &lt;strong&gt;"Hello World"&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpmgcfe3rioqvlngzslyr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpmgcfe3rioqvlngzslyr.png" alt="Hello World" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This creates a new ASP.NET Core minimal web API. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Run the Web App by executing the following command: &lt;strong&gt;dotnet run&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The output will show a URL (e.g., &lt;a href="https://localhost:5065" rel="noopener noreferrer"&gt;https://localhost:5065&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1irv2o8zekm8jubd7kp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1irv2o8zekm8jubd7kp.png" alt="output" width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the URL in a web browser to see the web app running.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68ljg6h41p0tyryjjsx6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68ljg6h41p0tyryjjsx6.png" alt="web app running" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modify the Web App Code&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the left up panel, click on &lt;strong&gt;mywebapp&lt;/strong&gt; and on dropdown click on &lt;strong&gt;Program.cs&lt;/strong&gt; to open and modify it as follows:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpjv87qpgrp6t3gjebei6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpjv87qpgrp6t3gjebei6.png" alt="Program.cs" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebApplication.CreateBuilder(args)&lt;/strong&gt; – Sets up a new web application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;builder.Build()&lt;/strong&gt; – Builds the application instance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;app.MapGet("/", () =&amp;gt; "Hello, Web!");&lt;/strong&gt; – Defines a route that returns "Hello, Web!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;app.Run();&lt;/strong&gt; – Runs the web application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a Simple C# Console App&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new folder/diretory by running the command: &lt;strong&gt;mkdir (directory/folder name)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd92o211b1yeh7vukxq3t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd92o211b1yeh7vukxq3t.png" alt="mkdir " width="800" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the directory/folder with the command: &lt;strong&gt;cd (directory/folder name)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86aa7phyn20b5gacxpys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86aa7phyn20b5gacxpys.png" alt="Open the directory" width="800" height="57"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To create a new console application, give it a name, put it inside new directory/folder, run the command: &lt;strong&gt;dotnet new console -n MyConsoleapptest -o .&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feabltm6yol0nob9lokn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feabltm6yol0nob9lokn7.png" alt="To create a new console application" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To verify the console application created: on the left side, click on &lt;strong&gt;my-console&lt;/strong&gt;, on the dropdown, then click on &lt;strong&gt;program.cs&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxe3g0it398wyvfmiw9pc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxe3g0it398wyvfmiw9pc.png" alt="To verify the console application" width="800" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the console app using the command: &lt;strong&gt;dotnet run&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq56vbol5uzhqiham49b1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq56vbol5uzhqiham49b1.png" alt="dotnet run" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modify the Console App Code&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open Program.cs and modify it as follows: Replace the &lt;strong&gt;"hello word!"&lt;/strong&gt; with *&lt;em&gt;"I am learning the foundation of c#" *&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;On the terminal run the command &lt;strong&gt;dotnet build&lt;/strong&gt; and then followed by the command &lt;strong&gt;dotnet run&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxg50xgaovh3g6lhdyq1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxg50xgaovh3g6lhdyq1.png" alt="I am learning the foundation of c#" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running a kids maths game: In program.cs, write the kids maths game console c# code, then on the terminal run the command &lt;strong&gt;dotnet build&lt;/strong&gt; and after that run the command &lt;strong&gt;dotnet run.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now the kids maths game is running.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1tk7bgqdjfffsqq1k8n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1tk7bgqdjfffsqq1k8n.png" alt="kids maths game" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Difference Between a Console Application and a Web Application in C#&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're new to programming, think of a console application as a calculator you use by typing commands, while a web application is like a website you visit in a browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Console Application (C#)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is it?&lt;/strong&gt;&lt;br&gt;
A console application is a text-based program that runs inside a terminal or command prompt.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example in real life:&lt;/strong&gt;
Imagine an old-school pocket calculator. You enter numbers, press a button, and it gives you a result. No fancy graphics, just text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where does it run?&lt;/strong&gt;
Runs on your computer using a command-line interface (like Command Prompt or Terminal).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How does the user interact?&lt;/strong&gt;
You type commands and see responses printed on the screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Web Application (C#)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;What is it?&lt;br&gt;
A web application is a program that runs inside a web browser and is accessed via the internet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example in real life:&lt;/strong&gt;
Imagine Facebook or Google, you open a website, click buttons, and interact with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where does it run?&lt;/strong&gt;
It runs on a web server and users access it through a web browser (like Chrome, Edge, or Firefox).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;We have successfully:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Installed VS Code and the required extensions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Built and ran a basic web application using ASP.NET Core.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Created a simple C# console application and understood how it works.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From here, you can expand your project by adding more features and exploring C# development further!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>csharp</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Understanding Load Balancers: A Step-by-Step Guide in creating a load balancer in Azure</title>
      <dc:creator>Kosisochukwu Ugochukwu</dc:creator>
      <pubDate>Fri, 14 Mar 2025 14:31:36 +0000</pubDate>
      <link>https://dev.to/kosisochukwu_ugochukwu_a2/understanding-load-balancers-a-step-by-step-guide-in-creating-a-load-balancer-in-azure-36mf</link>
      <guid>https://dev.to/kosisochukwu_ugochukwu_a2/understanding-load-balancers-a-step-by-step-guide-in-creating-a-load-balancer-in-azure-36mf</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;What is a Load Balancer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A load balancer is a tool used to spread incoming network traffic among several servers so as to prevent overload of any one server. Think of it as a traffic police officer who directs cars (data requests) to different open lanes (servers) to avoid congestion and delays.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is a Load Balancer Useful?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improves Performance:&lt;/strong&gt; It ensures faster response times by balancing the workload across multiple servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensures High Availability:&lt;/strong&gt; If one server goes down, the load balancer redirects traffic to healthy servers, keeping applications running.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhances Security:&lt;/strong&gt; It can protect against cyber-attacks like Distributed Denial-of-Service (DDoS) by distributing traffic efficiently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Types of Load Balancers in Azure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Azure provides different types of load balancers to cater to various needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Azure Load Balancer&lt;/strong&gt; (Layer 4 – Transport Layer): Used for distributing traffic within a Virtual Network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure Application Gateway&lt;/strong&gt; (Layer 7 – Application Layer): Provides additional features like SSL termination and routing traffic based on URL paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure Traffic Manager&lt;/strong&gt;: Used for DNS-based traffic distribution across different geographic locations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure Front Door&lt;/strong&gt;: Optimized for web applications by routing traffic based on performance, security, and latency.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step-by-Step Guide to Creating a Load Balancer in Azure
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Log in to Azure Portal&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open your web browser and go to &lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Sign in using your Microsoft Azure account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F131v6u18qie58e6unrsw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F131v6u18qie58e6unrsw.png" alt="Sign in using" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Create a New Load Balancer&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the search bar at the top, type &lt;strong&gt;"Load Balancer"&lt;/strong&gt; and select &lt;strong&gt;"Load Balancers"&lt;/strong&gt; from the results.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66dn48xao84wcrhvwb7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66dn48xao84wcrhvwb7f.png" alt="Load Balancers" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;"Create"&lt;/strong&gt; to begin setting up your load balancer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjwdvln2s6lgvc90yff3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjwdvln2s6lgvc90yff3.png" alt="Create" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"notice the type on the left panel marked"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Configure the Basic Settings&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subscription:&lt;/strong&gt; Select your Azure subscription.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Group:&lt;/strong&gt; Choose an &lt;strong&gt;existing resource group&lt;/strong&gt; or &lt;strong&gt;create a new one.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Region:&lt;/strong&gt; Pick the Azure region where you want to deploy the load balancer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Name:&lt;/strong&gt; Provide a &lt;strong&gt;name&lt;/strong&gt; for your load balancer (e.g., "MyLoadBalancer1").&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SKU:&lt;/strong&gt; Choose &lt;strong&gt;Standard&lt;/strong&gt;, Gateway, or &lt;strong&gt;Basic&lt;/strong&gt; (Standard is recommended for production use since it distributes traffic to backend resources).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Type:&lt;/strong&gt; Select either &lt;strong&gt;Public&lt;/strong&gt; (for internet-facing applications) or &lt;strong&gt;Internal&lt;/strong&gt; (for internal network applications). For the purpose of this tutorial, we choose public&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tier:&lt;/strong&gt; Select either &lt;strong&gt;Regional&lt;/strong&gt; or &lt;strong&gt;Global&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Next: Frontend IP Configuration&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiv67el74k0eyh4he0qr6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiv67el74k0eyh4he0qr6.png" alt="Frontend IP Configuration" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Configure the Frontend IP&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;+ Add a frontend IP&lt;/strong&gt; configuration."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7pz4ymisdcgbb71e8u8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7pz4ymisdcgbb71e8u8.png" alt="+ Add a frontend IP" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide a name for the frontend IP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyyjebdy453flu3kunwe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyyjebdy453flu3kunwe.png" alt="Provide a name" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new &lt;strong&gt;Public IP&lt;/strong&gt; if you are using a public load balancer or select &lt;strong&gt;Private IP&lt;/strong&gt; for internal use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqy0v4dcmwakmhkut0w2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqy0v4dcmwakmhkut0w2.png" alt="Public IP" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give the public address a name&lt;/li&gt;
&lt;li&gt;Avaliability zone choose zone redundant or no zone&lt;/li&gt;
&lt;li&gt;Click save&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next: Backend pools&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzwibm1p7zqx1tgxk4ce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzwibm1p7zqx1tgxk4ce.png" alt="Backend pools" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Configure the Backend Pool&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;+ Add a backend pool.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomrtaw366am6n5qysu5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomrtaw366am6n5qysu5h.png" alt="+ Add a backend pool" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give it a name (e.g., "BackendPool1").&lt;/li&gt;
&lt;li&gt;On the Virtual network: Select &lt;strong&gt;Virtual Machines&lt;/strong&gt; as the backend.&lt;/li&gt;
&lt;li&gt;Add the Virtual Machines that will receive the traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgdj2dlypuvyljld91d7d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgdj2dlypuvyljld91d7d.png" alt="Virtual network" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vdu79svc4s3gavaqe5r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vdu79svc4s3gavaqe5r.png" alt="Virtual network2" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Next: Inbound rules&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9j8nkscrxu6ycfrkaiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9j8nkscrxu6ycfrkaiw.png" alt="Inbound rules" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7: Configure Load Balancing Rules&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;+ Add a load balancing rule.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gri0rheaachfkf67w6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gri0rheaachfkf67w6u.png" alt="+ Add a load balancing rule" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide a name for the rule (e.g., "LBRule1").&lt;/li&gt;
&lt;li&gt;Set the frontend IP configuration.&lt;/li&gt;
&lt;li&gt;Choose the backend pool created earlier.&lt;/li&gt;
&lt;li&gt;Select the protocol (TCP, or UDP).&lt;/li&gt;
&lt;li&gt;Set the port (e.g., 80 for web traffic).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuf948w7tjlpez4apwk6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuf948w7tjlpez4apwk6b.png" alt="Set the port" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Health probe: &lt;strong&gt;Click create new&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj57mvdgz6exer611yqgj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj57mvdgz6exer611yqgj.png" alt="Health probe" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give it a name (e.g., "HealthProbe").&lt;/li&gt;
&lt;li&gt;Select the protocol (TCP, HTTP, or HTTPS).&lt;/li&gt;
&lt;li&gt;Set a port (e.g., 80 for HTTP traffic).&lt;/li&gt;
&lt;li&gt;Configure probe intervals (recommended: 5 seconds).&lt;/li&gt;
&lt;li&gt;Then click &lt;strong&gt;save&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcc0827li2uvuux0fdfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcc0827li2uvuux0fdfe.png" alt="click save" width="482" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then click &lt;strong&gt;Review + Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ifln06w1d1x1r4zvq4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ifln06w1d1x1r4zvq4s.png" alt="Review + Create" width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt; to deploy your load balancer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10btsuemz6m9k5umr18j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10btsuemz6m9k5umr18j.png" alt="Create" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deployment in progress&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhajatexz27dltttw3yt3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhajatexz27dltttw3yt3.png" alt="Deployment in progress" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 8: Test the Load Balancer&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open a web browser or use a tool like &lt;strong&gt;curl&lt;/strong&gt; to test the public IP of the load balancer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhybm7l1k1yokzn1957o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhybm7l1k1yokzn1957o.png" alt="web browser" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If configured correctly, traffic will be distributed among backend virtual machines.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;An Azure Load Balancer is a powerful tool for improving application speed, availability, and security. By following this step-by-step instruction, you will be able to successfully create and configure a load balancer to effectively control traffic in your Azure environment.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>cloud</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
