<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ship And Learn]]></title><description><![CDATA[I build stuff, things break, I learn why. Writing it all down here.]]></description><link>https://blog.akshanshsingh.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 21 May 2026 21:31:48 GMT</lastBuildDate><atom:link href="https://blog.akshanshsingh.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[I Built a Time Capsule App to Learn Spring Boot — Here's How It Went]]></title><description><![CDATA[Took a long break from writing. Didn't plan to, just happened. But I'm back, and I figured what better way to return than tearing apart something I actually built. I wanted a real project to learn Spr]]></description><link>https://blog.akshanshsingh.com/i-built-a-time-capsule-app-to-learn-spring-boot-here-s-how-it-went</link><guid isPermaLink="true">https://blog.akshanshsingh.com/i-built-a-time-capsule-app-to-learn-spring-boot-here-s-how-it-went</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Java]]></category><category><![CDATA[webdev]]></category><category><![CDATA[Build In Public]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Thu, 21 May 2026 10:42:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6794ab7d9b132f5cc275cec9/71310068-70d7-4e0c-a31f-92cdfa48f6c1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<p>Took a long break from writing. Didn't plan to, just happened. But I'm back, and I figured what better way to return than tearing apart something I actually built. I wanted a real project to learn Spring Boot properly. Not a tutorial. Not a todo app. Something with enough moving parts that I'd actually have to figure things out — auth, background jobs, file storage, the whole thing. So I built Time Capsule: a web app where you can create sealed digital capsules with messages and photos, lock them, and have them automatically delivered on a future date you set.</p>
<p>The idea is simple. The implementation was not.</p>
<h2>What It Actually Does</h2>
<p>You create a capsule, add content to it — text, images, files — set an unlock date, and that's it. The capsule is sealed. Nobody (including you) can see the contents until that date hits. You can invite other people as contributors or viewers. When the unlock date arrives, everyone gets an email notification and the capsule opens.</p>
<p>The features list sounds clean. Getting there was... a process.</p>
<h2>The Stack</h2>
<p><strong>Frontend:</strong> Next.js 14 (App Router), Tailwind CSS, Radix UI, Zustand for state, React Hook Form + Zod for validation.</p>
<p><strong>Backend:</strong> Spring Boot 3.x, Java 21, PostgreSQL, Spring Security + JWT, Spring Data JPA, Flyway for migrations, Amazon S3 for file storage, Resend for email notifications, and Spring's <code>@Scheduled</code> for background jobs.</p>
<p>I picked this stack specifically because I was weak on the backend side. I knew React well enough. Spring Boot was the gap I wanted to close.</p>
<h2>What Broke Me: JWT Auth</h2>
<p>I'll be honest — I underestimated this completely.</p>
<p>The filter chain, the <code>OncePerRequestFilter</code>, plugging everything into <code>SecurityFilterChain</code> correctly — it took way longer than it should have. Here's the actual filter I ended up with:</p>
<pre><code class="language-java">@Component
@RequiredArgsConstructor
@Slf4j
public class JwtAuthFilter extends OncePerRequestFilter {
    private final JwtUtil jwtUtil;
    private final UserDetailsServiceImpl userDetailsService;

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String servletPath = request.getServletPath();
        return servletPath.startsWith("/api/v1/oauth2/") ||
                servletPath.startsWith("/api/v1/login/oauth2/") ||
                servletPath.startsWith("/api/v1/auth/");
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");

        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }

        String token = authHeader.substring(7);

        try {
            if (jwtUtil.isTokenValid(token)) {
                String email = jwtUtil.extractEmail(token);
                UserDetails principal = userDetailsService.loadUserByUsername(email);

                var authToken = new UsernamePasswordAuthenticationToken(
                        principal, null, principal.getAuthorities()
                );
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        } catch (JwtException e) {
            request.setAttribute("jwt_exception", e);
            SecurityContextHolder.clearContext();
            return;
        } catch (UsernameNotFoundException e) {
            request.setAttribute("username_not_found_exception", e);
            SecurityContextHolder.clearContext();
            return;
        }

        filterChain.doFilter(request, response);
    }
}
</code></pre>
<p>The filter itself wasn't the hard part. The surprise was that exceptions thrown here never reach your <code>@ControllerAdvice</code> / <code>GlobalExceptionHandler</code> — because this filter runs <em>before</em> the request ever enters the controller layer. I kept wondering why my exception handler was doing nothing.</p>
<p>The fix was a <code>CustomAuthenticationEntryPoint</code> registered directly in <code>SecurityConfig</code>:</p>
<pre><code class="language-java">.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(exception -&gt; exception
        .authenticationEntryPoint(authenticationEntryPoint));
</code></pre>
<p>One line, but it took me an embarrassingly long time to figure out <em>why</em> it was needed. Spring Security's error handling is a different world from what you're used to coming from Express or Next.js API routes.</p>
<p>Role-based access was its own thing. Three roles: <code>OWNER</code>, <code>CONTRIBUTOR</code>, and <code>VIEWER</code>. Enforcing this at the service layer rather than just the controller made the code cleaner — but also meant more places for something to silently fail.</p>
<h2>What Else Broke Me: S3</h2>
<p>File uploads felt straightforward on paper. In practice, I had three separate issues:</p>
<p><strong>CORS.</strong> When a capsule unlocks and the frontend tries to render images via presigned S3 URLs, the browser blocks the request if your S3 bucket CORS policy doesn't allow your origin. The error message is useless — it took me a while to trace it back to a missing CORS rule in the bucket config rather than anything in my own code.</p>
<p><strong>File size limits.</strong> Spring Boot has a default multipart upload limit of 1MB. My app is supposed to support "high-quality images." I kept getting <code>MaxUploadSizeExceededException</code> until I added this to <code>application.properties</code>:</p>
<pre><code class="language-properties">spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
</code></pre>
<p><strong>Presigned URLs for access control.</strong> Uploads go frontend → Spring Boot → S3 — the server handles all file storage. But the more interesting part is how files are <em>served back</em>. The S3 bucket stays private by default; nothing is publicly accessible. When a capsule unlocks, the backend generates a presigned URL for each file: a temporary, expiring S3 link valid for a limited window. That URL gets handed to the frontend, which renders the image. The file was sitting in S3 the whole time, completely unreachable until unlock. It's a clean way to enforce the sealed capsule mechanic at the storage layer, not just the app layer.</p>
<h2>The Part I Actually Liked: Scheduled Jobs</h2>
<p>The core mechanic of the whole app is that capsules unlock automatically. No cron job on the server, no manual trigger. Spring's <code>@Scheduled</code> annotation makes this almost embarrassingly easy.</p>
<pre><code class="language-java">@Transactional
@Scheduled(fixedDelay = 60000)      // runs every 60 secs
    public void unlockDueCapsules(){
        List&lt;Capsule&gt; dueCapsules = capsuleRepository
                .findAllDueCapsulesWithDetails(Instant.now());


        for(Capsule capsule : dueCapsules){
            capsule.setStatus(CapsuleStatus.UNLOCKED);
            capsuleRepository.save(capsule);

            log.info("Capsule: {}, unlocked from scheduler at: {}", capsule.getSlug(), Instant.now());

            // Send emails to capsule members
            resendEmailService.sendUnlockNotification(capsule);
        }
    }
</code></pre>
<p>Every 60 seconds, it checks for capsules whose unlock date has passed, flips their status, and fires off email notifications. That's it. I used Resend for the emails — clean API, took maybe 30 minutes to integrate.</p>
<p>This was the part of the backend I felt most confident building, which says something about how the auth and S3 sections went.</p>
<h2>Architecture</h2>
<p>Here's the full system diagram:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6794ab7d9b132f5cc275cec9/c1fd1505-bc1b-497a-b7c1-f85fea1074dd.png" alt="" style="display:block;margin:0 auto" />

<p>Two layers — client and server — with clear separation between them.</p>
<p><strong>Client layer:</strong> The user hits the Next.js frontend over HTTPS. All API calls go to Spring Boot with a JWT attached in the <code>Authorization</code> header. That's it for the frontend's job.</p>
<p><strong>Server layer:</strong> Spring Boot is the hub. It handles three distinct flows:</p>
<ol>
<li><p><strong>Data flow</strong> — REST requests from the frontend hit the API, which reads/writes capsule data to PostgreSQL via JPA. Standard CRUD, nothing unusual here.</p>
</li>
<li><p><strong>File flow</strong> — When a user attaches a file to a capsule, it routes frontend → Spring Boot → S3. The bucket is private by default. When a capsule unlocks, the backend generates presigned URLs — temporary, expiring S3 links — so the frontend can render the files without ever making them publicly accessible.</p>
</li>
<li><p><strong>Scheduler flow</strong> — The <code>Task Scheduler</code> (Spring's <code>@Scheduled</code>) runs in the background independently of any HTTP request. When a capsule's unlock date passes, it updates the capsule state in PostgreSQL and triggers the SMTP mail server to send email notifications out to all participants.</p>
</li>
</ol>
<p>That last flow — the async, time-driven one — is what makes the app actually work. Everything else is just a web app. The scheduler is what gives it its whole point.</p>
<h2>What I'd Do Differently</h2>
<p>The app works. It's deployed at <a href="https://timecapsule.akshanshsingh.com">timecapsule.akshanshsingh.com</a>. But if I started over:</p>
<p><strong>I'd plan the data model first.</strong> I made a few schema decisions early that I had to undo later. Flyway migrations saved me here, but the back-and-forth was avoidable.</p>
<p><strong>I'd handle errors more consistently on the frontend.</strong> Some API errors surface nicely. Others fail silently. Users deserve better than that.</p>
<p><strong>I'd containerize earlier.</strong> Docker is on the roadmap but I kept pushing it off. Starting with a <code>docker-compose.yml</code> would've made the local dev setup way less painful to explain to anyone who wanted to run it.</p>
<p><strong>I'd generate presigned URLs more granularly.</strong> Right now they're generated at unlock time for all files in a capsule. In hindsight I'd scope them tighter — shorter expiry, per-request generation — so there's no window where a URL stays valid longer than it should.</p>
<h2>What's Next</h2>
<ul>
<li><p>Full Dockerization for one-click deployment</p>
</li>
<li><p>In-app audio player for sound-based memories</p>
</li>
<li><p>Search and filter for public vaults</p>
</li>
</ul>
<p>The core feature set is solid. The polish is what's left.</p>
<hr />
<p>This was the most complete full-stack project I've shipped so far. Spring Boot clicked for me around week three. Java stopped feeling verbose and started feeling structured. The backend patterns — services, repositories, controllers — make a lot of sense once you build something non-trivial with them.</p>
<p>If you're coming from a JavaScript background and considering Spring Boot: the learning curve is real, but it's worth it. Just expect JWT to humble you first.</p>
<p>What part of a full-stack project do you find hardest to get right — auth, storage, or something else entirely?</p>
]]></content:encoded></item><item><title><![CDATA[Mastering Terraform State Management and Workspaces Through Real Projects]]></title><description><![CDATA[Introduction
Hello readers👋! Past 3 weeks have been hectic to be honest and I wasn't able to get a lot done but still managed to take some time to learn and create something. I continued where I left off from my previous Terraform article and dove d...]]></description><link>https://blog.akshanshsingh.com/mastering-terraform-state-management-and-workspaces-through-real-projects</link><guid isPermaLink="true">https://blog.akshanshsingh.com/mastering-terraform-state-management-and-workspaces-through-real-projects</guid><category><![CDATA[Devops]]></category><category><![CDATA[DevOps Journey]]></category><category><![CDATA[learning]]></category><category><![CDATA[Terraform]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Infrastructure as code]]></category><category><![CDATA[infrastructure]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sun, 21 Sep 2025 06:56:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758437624630/87d883c1-d70a-4494-b256-6f2c8507f2b4.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello readers👋! Past 3 weeks have been hectic to be honest and I wasn't able to get a lot done but still managed to take some time to learn and create something. I continued where I left off from my previous Terraform article and dove deep into two crucial concepts that every Terraform practitioner needs to master - <strong>State Management</strong> and <strong>Workspaces</strong>. And to practice and get some hands-on experience of using Terraform, I've built a mini project and a real-life industry standard project to enhance my understanding and workflow of Terraform.</p>
<p>After understanding the basics of Terraform in my previous article, I realized that knowing how to write <code>.tf</code> files is just the beginning. The real challenge comes when you need to manage infrastructure across different environments, collaborate with teams, and ensure that your infrastructure state is consistent and secure.</p>
<h2 id="heading-state-management-and-workspaces">State Management and Workspaces</h2>
<h3 id="heading-understanding-terraform-state">Understanding Terraform State</h3>
<p>Before diving into advanced state management, I had to understand what exactly the <strong>state</strong> is in Terraform. The state is basically Terraform's way of keeping track of the real-world resources it manages. When you run <code>terraform apply</code>, Terraform doesn't just create resources - it also records information about those resources in a state file (<code>terraform.tfstate</code>).</p>
<p>This state file contains:</p>
<ul>
<li><p><strong>Resource metadata</strong> - IDs, current configuration, and dependencies</p>
</li>
<li><p><strong>Resource mappings</strong> - How your <code>.tf</code> configuration maps to real-world resources</p>
</li>
<li><p><strong>Performance optimization</strong> - Instead of querying all resources every time, Terraform uses state for faster operations</p>
</li>
</ul>
<p>The problem I learned about is that by default, Terraform stores state locally, which creates several challenges:</p>
<ul>
<li><p><strong>Collaboration issues</strong> - Multiple team members can't work on the same infrastructure</p>
</li>
<li><p><strong>State loss</strong> - If your local machine crashes, you lose track of your infrastructure</p>
</li>
<li><p><strong>Security risks</strong> - State files contain sensitive information and shouldn't be stored in version control</p>
</li>
</ul>
<h3 id="heading-remote-state-management">Remote State Management</h3>
<p>To solve these problems, I learned about <strong>remote state backends</strong>. A backend in Terraform determines where and how state is stored and accessed. The most commonly used backend for AWS environments is <strong>S3 with DynamoDB</strong>.</p>
<p>Here's how I configured remote state in my projects:</p>
<pre><code class="lang-plaintext">terraform {
  backend "s3" {
    bucket         = "terraform-state-bucket-akshansh029"
    key            = "dev/terraform.tfstate"
    region         = "ap-south-1"
    dynamodb_table = "terraform-state-lock"
    encrypt        = true
  }
}
</code></pre>
<p>The <strong>S3 bucket</strong> stores the actual state file, while <strong>DynamoDB</strong> provides state locking to prevent multiple people from running Terraform simultaneously on the same infrastructure. The <code>encrypt = true</code> ensures that the state file is encrypted at rest.</p>
<h3 id="heading-terraform-workspaces">Terraform Workspaces</h3>
<p>After understanding state management, I learned about <strong>Workspaces</strong> - a feature that allows you to manage multiple environments (dev, staging, prod) using the same Terraform configuration.</p>
<p>Think of workspaces as separate "instances" of your infrastructure. Each workspace has its own state file, so you can have identical infrastructure setups for different environments without them interfering with each other.</p>
<p>Key workspace commands I learned:</p>
<ul>
<li><p><code>terraform workspace list</code> - Shows all available workspaces</p>
</li>
<li><p><code>terraform workspace new &lt;name&gt;</code> - Creates a new workspace</p>
</li>
<li><p><code>terraform workspace select &lt;name&gt;</code> - Switches to a specific workspace</p>
</li>
<li><p><code>terraform workspace show</code> - Shows current workspace</p>
</li>
</ul>
<p>What's really cool about workspaces is that you can use the <code>terraform.workspace</code> variable in your configurations to make environment-specific decisions:</p>
<pre><code class="lang-plaintext">resource "aws_instance" "example" {
  instance_type = terraform.workspace == "prod" ? "t3.medium" : "t2.micro"

  tags = {
    Name = "${terraform.workspace}-server"
    Environment = terraform.workspace
  }
}
</code></pre>
<h2 id="heading-mini-project-dev-and-prod-infrastructure">Mini Project: Dev and Prod Infrastructure</h2>
<p>To practice these concepts, I created a mini project that demonstrates how to use workspaces to manage identical infrastructure across different environments.</p>
<h3 id="heading-project-structure">Project Structure</h3>
<p>I organized my project with the following structure:</p>
<pre><code class="lang-plaintext">DevOps-Learning/terraform-modules-app/
├── main.tf
├── provider.tf
├── terraform.tf
├── app
        ├── dynamo.tf
        ├── ec2.tf
        ├── s3.tf
        ├── variables.tf
</code></pre>
<h3 id="heading-environment-specific-configuration">Environment-Specific Configuration</h3>
<p>The importance of this project was seeing how the same Terraform configuration could create different infrastructure based on the workspace. Here's how I implemented environment-specific logic:</p>
<pre><code class="lang-plaintext"># Different instance types for different environments
resource "aws_instance" "web_server" {
  ami           = var.ami_id
  instance_type = terraform.workspace == "prod" ? var.prod_instance_type : var.dev_instance_type
  key_name      = aws_key_pair.deployer.key_name

  # Different storage sizes
  root_block_device {
    volume_size = terraform.workspace == "prod" ? 20 : 8
    volume_type = "gp3"
  }

  tags = {
    Name = "${terraform.workspace}-web-server"
    Environment = terraform.workspace
  }
}
</code></pre>
<h3 id="heading-workflow-implementation">Workflow Implementation</h3>
<p>The workflow I followed was:</p>
<ol>
<li><strong>Create Dev Environment:</strong></li>
</ol>
<pre><code class="lang-bash">terraform workspace new dev
terraform plan
terraform apply
</code></pre>
<ol>
<li><strong>Create Prod Environment:</strong></li>
</ol>
<pre><code class="lang-bash">terraform workspace new prod
terraform plan
terraform apply
</code></pre>
<p>Each environment got its own EC2 instance with appropriate sizing, security groups, but they were completely isolated from each other thanks to workspaces.</p>
<h2 id="heading-2-tier-aws-infrastructure-terraform-project">2-Tier-AWS-Infrastructure-Terraform Project</h2>
<p>After getting comfortable with workspaces, I decided to tackle a more comprehensive project - a <strong>2-tier AWS infrastructure</strong> that follows industry standards and best practices.</p>
<h3 id="heading-project-architecture">Project Architecture</h3>
<p>This project implements a typical web application architecture with:</p>
<p><strong>Presentation Tier (Web Layer):</strong></p>
<ul>
<li><p>Application Load Balancer for traffic distribution</p>
</li>
<li><p>Auto Scaling Group with EC2 instances in multiple Availability Zones</p>
</li>
<li><p>Launch Template with user data for automatic application setup</p>
</li>
</ul>
<p><strong>Data Tier (Database Layer):</strong></p>
<ul>
<li><p>RDS MySQL database with Multi-AZ deployment</p>
</li>
<li><p>Private subnets for database security</p>
</li>
<li><p>Database subnet group for proper placement</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758437705116/64d8a1fe-ee42-4949-93e2-4d4fd281ce23.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-infrastructure-deep-dive">Infrastructure Deep Dive</h3>
<p>The 2-tier architecture I implemented consists of two main layers that work together to create a scalable and secure web application infrastructure:</p>
<p><strong>Web Tier (Presentation Layer):</strong> This is the front-facing layer that handles all user requests. I created an Application Load Balancer that distributes incoming traffic across multiple EC2 instances running in different Availability Zones. The EC2 instances are part of an Auto Scaling Group, which means they can automatically scale up or down based on traffic demand. Each instance runs a web server (I used Apache with a simple HTML page) that serves the application content to users.</p>
<p><strong>Database Tier (Data Layer):</strong> The second tier consists of an RDS MySQL database that stores all the application data. What's really important here is that the database is placed in private subnets, meaning it's not directly accessible from the internet. Only the web servers can communicate with the database through internal network routing.</p>
<h3 id="heading-implementation-process-and-workflow">Implementation Process and Workflow</h3>
<p><strong>Phase 1: Network Foundation</strong> I started by building the network infrastructure - creating a custom VPC with both public and private subnets across multiple Availability Zones. The public subnets host the web servers and load balancer, while the private subnets contain the database. An Internet Gateway provides internet access to the public subnets, and a NAT Gateway allows the private subnets to download updates and patches while remaining secure.</p>
<p><strong>Phase 2: Compute Layer Setup</strong> Next, I implemented the compute resources using a Launch Template that defines the EC2 instance configuration. The Launch Template includes the AMI, instance type, security groups, and a user data script that automatically installs and configures Apache web server when instances launch. The Auto Scaling Group uses this template to maintain the desired number of healthy instances and can automatically replace failed instances.</p>
<p><strong>Phase 3: Database Implementation</strong> For the database layer, I created an RDS MySQL instance with Multi-AZ deployment for high availability. The database is configured with automated backups, encryption at rest, and is placed in a database subnet group that spans multiple Availability Zones. I also implemented parameter groups to optimize database performance.</p>
<p><strong>Phase 4: Load Balancing and Traffic Management</strong> The Application Load Balancer sits in the public subnets and routes traffic to healthy web server instances based on configured health checks. I set up target groups that define which instances should receive traffic and configured the load balancer to distribute requests evenly across all available instances.</p>
<h3 id="heading-security-architecture">Security Architecture</h3>
<p>Security was implemented at multiple layers throughout the infrastructure:</p>
<p><strong>Network Security:</strong> I created separate security groups for each tier - the load balancer security group allows HTTP/HTTPS traffic from the internet, the web server security group only accepts traffic from the load balancer, and the database security group only allows MySQL connections from the web servers. This creates a secure communication path where each layer only accepts traffic from the layer above it.</p>
<p><strong>Database Security:</strong> The RDS instance is completely isolated in private subnets with no direct internet access. Database credentials are managed securely, and I enabled encryption both at rest and in transit. The database is also configured with automated backups and point-in-time recovery.</p>
<p><strong>Access Control:</strong> I used IAM roles instead of hardcoded credentials, and implemented the principle of least privilege throughout the infrastructure. The EC2 instances have just enough permissions to function but can't access other AWS services unnecessarily.</p>
<h3 id="heading-project-flow">Project Flow</h3>
<p>The beauty of this infrastructure is how all the components work together automatically:</p>
<ol>
<li><p><strong>Traffic Flow:</strong> When users access the application, their requests hit the Application Load Balancer, which checks the health of all web server instances and routes the request to a healthy server.</p>
</li>
<li><p><strong>Auto Scaling:</strong> If traffic increases, the Auto Scaling Group automatically launches new EC2 instances using the Launch Template. These new instances automatically register with the load balancer target group and start receiving traffic.</p>
</li>
<li><p><strong>Database Connectivity:</strong> The web servers connect to the RDS database using the internal DNS endpoint, ensuring all data operations happen securely within the private network.</p>
</li>
<li><p><strong>Failure Recovery:</strong> If an EC2 instance fails, the Auto Scaling Group automatically terminates it and launches a replacement. If the primary database fails, RDS automatically fails over to the standby instance in another Availability Zone.</p>
</li>
</ol>
<p>The best thing was seeing this entire infrastructure come to life with just a few Terraform commands. Running <code>terraform apply</code> creates dozens of resources in the correct order, with all the dependencies handled automatically by Terraform's dependency graph.</p>
<p><code>GitHub repo of this project</code>- <a target="_blank" href="https://github.com/Akshansh029/2-Tier-AWS-Infrastructure-Terraform">https://github.com/Akshansh029/2-Tier-AWS-Infrastructure-Terraform</a></p>
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p><strong>1️⃣ RDS Cluster Engine Version Problem</strong></p>
<p>When I initially tried to create an RDS cluster, I encountered an error related to the engine version. I had specified <code>engine_version = "8.0"</code> but AWS was expecting a more specific version like <code>8.0.35</code>.</p>
<p><em>Solution</em>: I learned to check available engine versions using the AWS CLI. Then I updated my configuration to use a specific version that was available in my region.</p>
<p><strong>2️⃣ State Lock Already Engaged</strong></p>
<p>This was frustrating! I was working on the project and my <code>terraform apply</code> command got interrupted. When I tried to run it again, I got a "state lock" error saying the state was already locked by a previous operation.</p>
<p><em>Solution</em>: I had to use the force-unlock command:</p>
<pre><code class="lang-bash">terraform force-unlock &lt;LOCK_ID&gt;
</code></pre>
<p><strong>3️⃣ Unable to Select Which Fields Are Required and Which Were Not in AWS Resource Creation</strong></p>
<p>While creating AWS resources, I was confused about which arguments were required and which were optional. The Terraform documentation sometimes wasn't clear, and I kept getting errors about missing required arguments.</p>
<p><em>Solution</em>: I had to rely more heavily on the official Terraform AWS provider documentation, search for better examples and use <code>terraform plan</code> extensively to catch missing required arguments before applying.</p>
<h2 id="heading-resources-i-used">Resources I Used</h2>
<ol>
<li><p><a target="_blank" href="https://developer.hashicorp.com/terraform/docs"><strong>Terraform Official Documentation</strong></a></p>
</li>
<li><p><a target="_blank" href="https://github.com/NotHarshhaa/DevOps-Projects/tree/master/DevOps-Project-11"><strong>DevOps Projects | NotHarshhaa</strong></a></p>
</li>
</ol>
<h2 id="heading-whats-next">What's Next</h2>
<p>After understanding the creation of cloud infrastructure using Terraform, my next plan is to learn configuration management of the infrastructure using <strong>Ansible</strong>. I want to understand how Terraform and Ansible work together’</p>
<h2 id="heading-lets-connect">Let's Connect!</h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>My LinkedIn</strong></a></p>
<p>🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I'd love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[A Beginner's Journey into Terraform and Infrastructure as Code]]></title><description><![CDATA[Hello readers 👋! Upon completing a couple of beginner Kubernetes projects, I am feeling confident about my understanding of core Kubernetes concepts. Kubernetes is much more vast than I currently know, so I will continue to learn more about it in th...]]></description><link>https://blog.akshanshsingh.com/a-beginners-journey-into-terraform-and-infrastructure-as-code</link><guid isPermaLink="true">https://blog.akshanshsingh.com/a-beginners-journey-into-terraform-and-infrastructure-as-code</guid><category><![CDATA[Devops]]></category><category><![CDATA[Terraform]]></category><category><![CDATA[Infrastructure as code]]></category><category><![CDATA[Learning Journey]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sun, 31 Aug 2025 17:14:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756660128801/b645a332-7fd4-4128-853e-ffe2b61723b2.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello readers 👋! Upon completing a couple of beginner Kubernetes projects, I am feeling confident about my understanding of core Kubernetes concepts. Kubernetes is much more vast than I currently know, so I will continue to learn more about it in the future. Last week, I got started with Infrastructure as Code and Terraform. In this article, I will be sharing my learnings from the past week.</p>
<h2 id="heading-infrastructure-as-code">Infrastructure as Code</h2>
<p>Before getting started with Terraform, one has to understand Infrastructure as Code, and I also started with the same question - <em>What is IaC?</em> Infrastructure as Code can be broken down into two terms - <strong>Infrastructure</strong> and <strong>Code</strong>.</p>
<p>Infrastructure refers to the underlying resources required to support applications and services, such as servers, networking components, operating systems, storage, databases, and security configurations. These resources are hidden from the user's eyes, but they are as important as the code of the application. Without these resources, an application cannot be deployed, maintained, and served to the audience.</p>
<p>Traditionally, physical/on-premises servers were used to deploy and maintain any application, with system administrators continuously monitoring everything. When the application's demand increased, the scaling process was done manually, and we all can imagine how painful and time-consuming that sounds.</p>
<p>But then the cloud revolution began. The evolution of cloud resources and providers such as AWS, GCP, Azure, Oracle, etc., came up with a solution to the traditional way of maintaining infrastructure for applications. The solution was to shift the focus from managing physical hardware to leveraging on-demand, scalable, and managed services over the internet. So now, instead of purchasing and configuring physical infrastructure, businesses can provision resources through cloud providers on a pay-per-use basis, significantly reducing upfront capital expenditures and operational costs.</p>
<p>However, with time, managing infrastructure through these cloud providers was becoming a pain too. Scaling up and down, replicating and tearing down infrastructure according to demand was becoming too time-consuming and was not fully automated.</p>
<h2 id="heading-terraform-origin">Terraform Origin</h2>
<p>AWS introduced their own IaC tool called <code>AWS CloudFormation</code>, which enables the automation and consistent provisioning of AWS resources through Infrastructure as Code. But this was only limited to AWS, forcing users and teams to use multiple tools for multi-cloud environments. This problem was highlighted by the co-founder of HashiCorp in 2011. Later in 2014, <strong>HashiCorp</strong> announced <code>Terraform</code> - an open-source Infrastructure as Code tool that could provide consistent workflows regardless of the cloud provider.</p>
<p>Terraform uses HCL (HashiCorp Configuration Language) to declare and provision resources across cloud providers. Terraform solves the complexity and fragility of managing infrastructure by turning it into code — making creation, change, and teardown of cloud (and some on-premises) resources <strong>repeatable, auditable, and automatable</strong>.</p>
<p>Some benefits of Terraform I learned:</p>
<ul>
<li><p><strong>Declarative:</strong> You describe <em>what</em> you want, not <em>how</em> to build it.</p>
</li>
<li><p><strong>Idempotent &amp; reproducible:</strong> Re-running the same configuration brings your infrastructure to the same desired state.</p>
</li>
<li><p><strong>Versionable:</strong> Configuration files live in Git like application code (review, branch, rollback).</p>
</li>
<li><p><strong>Multi-cloud &amp; provider ecosystem:</strong> Single tool to manage many providers.</p>
</li>
<li><p><strong>Plan/Apply safety:</strong> Previews changes before they happen.</p>
</li>
<li><p><strong>Modularity &amp; reuse:</strong> Modules let you package infrastructure patterns.</p>
</li>
</ul>
<h2 id="heading-terraform-basics">Terraform Basics</h2>
<p>After thoroughly understanding the concept of IaC and its necessity, I focused on learning the core concepts of Terraform. I started by installing Terraform using Chocolatey on my laptop.</p>
<p>The first concept was <strong>Provider</strong> - it is a plugin that knows how to create resources on a platform (e.g., AWS, Google). It allows users to interact with different APIs and services. <strong>Resource</strong> is a cloud object or service of a provider that the user manages, such as EC2 instances, S3 buckets, etc. These are provisioned with the help of Terraform, which communicates with the provider to create, configure, or delete the resources.</p>
<p>Then I learned HCL (HashiCorp Configuration Language), which is used to write Terraform files (.tf file extension). It is a structured configuration language created by HashiCorp. An HCL file contains <strong>blocks, arguments,</strong> and <strong>expressions.</strong></p>
<pre><code class="lang-plaintext">block_type "label1" "label2" {
  argument = value
}
</code></pre>
<p>Arguments are key-value pairs inside blocks where the configurations are written about the resource, and expressions are the values assigned to the arguments, which can be variables, references, or functions. I also learned about variables, comments, and other basic syntax.</p>
<p>Then it was time to learn about the core and important commands of Terraform:</p>
<ul>
<li><p><code>terraform init</code> - Initializes a Terraform working directory and downloads provider plugins and modules.</p>
</li>
<li><p><code>terraform validate</code> - Validates syntax and checks if the configuration is structurally correct.</p>
</li>
<li><p><code>terraform fmt</code> - Formats <code>.tf</code> files into a canonical style and ensures consistent formatting.</p>
</li>
<li><p><code>terraform plan</code> - Shows the execution plan of changes and compares current state vs desired state.</p>
</li>
<li><p><code>terraform apply</code> - Executes the changes shown in the plan.</p>
</li>
<li><p><code>terraform destroy</code> - Removes all managed infrastructure.</p>
</li>
</ul>
<p>These are the commands that are used most frequently in the Terraform workflow. Upon completing these basic but essential concepts, I decided to try creating some local and AWS resources using Terraform.</p>
<h2 id="heading-terraform-implementation">Terraform Implementation</h2>
<p>At first, I created a simple text file in the same repository with the help of the "local_file" resource like this:</p>
<pre><code class="lang-plaintext">resource "local_file" "my_file" {
  filename = "example.txt"
  content  = "First file created with Terraform"
}
</code></pre>
<p>After this, I tried to create an S3 bucket with a simple HCL file like this:</p>
<pre><code class="lang-plaintext">resource "aws_s3_bucket" "terraform_bucket" {
  bucket = "terraform-bucket-akshansh029"
}
</code></pre>
<p>After being able to create these simple resources with the help of Terraform's official documentation, I continued to learn advanced concepts like loops (count, for_each) and conditional expressions. Loops help users create multiple resources from a single block instead of duplicating them. The <code>count</code> argument creates N copies of the specified resource, whereas the <code>for_each</code> argument creates resources from a <strong>map</strong> or <strong>set</strong> of values. Along with these, I learned about interpolation arguments like user_data.</p>
<p>With these concepts, I then created multiple EC2 instances along with key-pairs, security groups, VPC, and installed Nginx on them by using a custom script in user_data like this:</p>
<pre><code class="lang-plaintext"># Key pair for EC2 instance
resource "aws_key_pair" "deployer" {
  key_name   = "terraform-ec2-key"
  public_key = file("terraform-ec2-key.pub")
}

# VPC for EC2 instance
resource "aws_default_vpc" "default" {}

# Security group for EC2 instance
resource "aws_security_group" "allow_tls" {
  name        = "terraform-ec2-sg"
  description = "Allow TLS inbound traffic and all outbound traffic"
  vpc_id      = aws_default_vpc.default.id # Interpolation

  # inbound rules
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    description = "SSH from anywhere"
  }
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    description = "Access to HTTP from anywhere"
  }

  # outbound rules
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "allow_tls"
  }
}

# EC2 Instance
resource "aws_instance" "terraform_ec2" {
  # count = 2 # meta argument
  for_each = tomap({
    terraform-ec2-instance-t2 = "t2.micro"
    terraform-ec2-instance-t3 = "t3.micro"
  })
  ami             = var.ubuntu_ec2_ami_id # Ubuntu 24
  instance_type   = each.value
  key_name        = aws_key_pair.deployer.key_name
  security_groups = [aws_security_group.allow_tls.name]
  root_block_device {
    volume_size = var.env == "prd" ? var.aws_root_storage_size : var.aws_default_root_storage_size
    volume_type = "gp3"
  }
  user_data = file("install_nginx.sh") # Run install_nginx script

  tags = {
    Name = each.key
  }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756659416978/40ae7a36-0a2e-456e-89db-51dd22c256a2.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756659392655/6ea3b5aa-8e77-4778-8f1f-717b22c363ce.png" alt /></p>
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p><strong>1. Didn't know which files not to push to GitHub</strong></p>
<p>While maintaining the GitHub repository for my Terraform learning, I committed and pushed <code>terraform.tfstate</code> to GitHub. Later, I learned that state files should never be pushed to GitHub because they contain sensitive information about your infrastructure and can lead to security vulnerabilities. The state file also creates conflicts when multiple team members are working on the same infrastructure. I immediately removed it from the repository and added it to <code>.gitignore</code>.</p>
<p><strong>2. Connection error during</strong> <code>terraform init</code></p>
<p>While trying to initialize Terraform using <code>terraform init</code>, I encountered this error:</p>
<pre><code class="lang-plaintext">│ Error: Failed to install provider │ │ Error while installing hashicorp/aws v6.11.0: │ releases.hashicorp.com: read tcp │ 172.20.146.187:54611-&gt;108.159.15.48:443: wsarecv: A │ connection attempt failed because the connected party │ did not properly respond after a period of time, or │ established connection failed because connected host │ has failed to respond.
</code></pre>
<p>This was a network connectivity issue where my college WiFi was blocking or limiting connections to HashiCorp's servers. The college network likely had firewall restrictions or proxy settings that prevented Terraform from downloading the required provider plugins. I solved this by switching to my personal mobile hotspot.</p>
<h2 id="heading-resources-i-used">Resources I Used</h2>
<ol>
<li><p><a target="_blank" href="https://developer.hashicorp.com/terraform/docs">Terraform Official Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/S9mohJI_R34?si=cFfPZ1ykKSAmh5ZE">TWS | Terraform Course</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/bEXfPzoB4RE?si=-Ygwa_yFe9Th7wqS">Kubesimplify | Terraform Crash Course</a></p>
</li>
</ol>
<h2 id="heading-whats-next">What’s Next</h2>
<p>I will continue to learn the advanced topics of Terraform and then to practice these, I will try to create an infrastructure using Terraform as a project.</p>
<h2 id="heading-lets-connect"><strong>Let's Connect!</strong></h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>My LinkedIn</strong></a></p>
<p>🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I'd love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Putting Kubernetes Knowledge to the Test]]></title><description><![CDATA[Introduction
Hello there 👋! Sorry for the delay with last week's article - exams kept me busy. The past couple of weeks of my DevOps learning journey have been incredibly rewarding. After completing my deep dive into Kubernetes concepts in the previ...]]></description><link>https://blog.akshanshsingh.com/putting-kubernetes-knowledge-to-the-test</link><guid isPermaLink="true">https://blog.akshanshsingh.com/putting-kubernetes-knowledge-to-the-test</guid><category><![CDATA[Devops]]></category><category><![CDATA[Learning Journey]]></category><category><![CDATA[learning]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Docker]]></category><category><![CDATA[ArgoCD]]></category><category><![CDATA[projects]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Mon, 18 Aug 2025 11:19:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755515858225/4ac89a30-56f1-4389-9960-3086c4971af7.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there 👋! Sorry for the delay with last week's article - exams kept me busy. The past couple of weeks of my DevOps learning journey have been incredibly rewarding. After completing my deep dive into Kubernetes concepts in the previous weeks, I decided it was time to put all that theoretical knowledge to the test. This week, I focused on building two comprehensive Kubernetes projects that would help me understand how all these concepts work together in real-world scenarios.</p>
<h2 id="heading-project-1-full-stack-chat-application-on-minikube">Project 1: Full-Stack Chat Application on MiniKube</h2>
<p>The first project I tackled was deploying a <strong>three-tier chat application</strong> consisting of a React.js frontend, Node.js backend, and MongoDB database. What I found interesting about this project was how it brought together so many Kubernetes concepts I had learned - deployments, services, persistent volumes, secrets, and ingress controllers.</p>
<h3 id="heading-architecture-and-components">Architecture and Components</h3>
<p>The application architecture was straightforward but comprehensive:</p>
<ul>
<li><p><strong>Frontend</strong>: React.js application for the user interface</p>
</li>
<li><p><strong>Backend</strong>: Node.js API server handling chat logic</p>
</li>
<li><p><strong>Database</strong>: MongoDB for storing chat messages and user data</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755514888313/46f70753-0f1f-4cdc-a04b-f060dc5b6c03.png" alt /></p>
</li>
</ul>
<h3 id="heading-key-kubernetes-concepts-applied">Key Kubernetes Concepts Applied</h3>
<p><strong>Persistent Storage</strong>: One of the most important aspects I learned was implementing persistent storage for MongoDB. I created a <strong>Persistent Volume</strong> and <strong>Persistent Volume Claim</strong> to ensure that chat data wouldn't be lost when pods were restarted. For MiniKube, I used <code>hostPath</code> which stores data directly on the host machine.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">PersistentVolume</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">mongodb-pv</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">capacity:</span>
    <span class="hljs-attr">storage:</span> <span class="hljs-string">1Gi</span>
  <span class="hljs-attr">accessModes:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">ReadWriteOnce</span>
  <span class="hljs-attr">hostPath:</span>
    <span class="hljs-attr">path:</span> <span class="hljs-string">/data/mongodb</span>
</code></pre>
<p><strong>Secrets Management</strong>: I learned how critical it is to properly handle sensitive information. The application required a JWT secret key and a MongoDB connection string, which I stored as Kubernetes secrets with Base64 encoding. This was my first real experience with securely managing credentials in Kubernetes.</p>
<p><strong>Service Discovery</strong>: While learning Kubernetes, what impressed me while learning Kubernetes was seeing how services could connect to each other simply using service names. When building this project, seeing the backend connect with MongoDB using just <code>mongodb:27017</code> demonstrated the automatic service discovery within the cluster perfectly.</p>
<p><strong>Ingress Controller</strong>: Instead of using port-forwarding for access, I configured an ingress controller to route traffic based on hostnames. I had to add <code>chats.aks.com</code> to my local hosts file to access the application through a custom domain.</p>
<h3 id="heading-docker-hub-integration">Docker Hub Integration</h3>
<p>Before deploying to Kubernetes, I had to build and push Docker images for both frontend and backend to Docker Hub. This step taught me about the importance of having images accessible to the cluster.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755514907431/1ace7c31-f598-4ac9-9c78-791eded578bb.png" alt /></p>
<h2 id="heading-project-2-voting-application-with-gitops-using-argocd">Project 2: Voting Application with GitOps using ArgoCD</h2>
<p>The second project was significantly more complex and introduced me to the world of <strong>GitOps</strong>. I deployed a microservices voting application using ArgoCD on a multi-node Kubernetes cluster running on AWS EC2.</p>
<h3 id="heading-infrastructure-setup">Infrastructure Setup</h3>
<p>I started by setting up a <strong>Kind (Kubernetes in Docker)</strong> cluster on an AWS EC2 instance. This is how I created a multi-node cluster configuration:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">kind:</span> <span class="hljs-string">Cluster</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">kind.x-k8s.io/v1alpha4</span>
<span class="hljs-attr">nodes:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">role:</span> <span class="hljs-string">control-plane</span>
  <span class="hljs-attr">image:</span> <span class="hljs-string">kindest/node:v1.30.0</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">role:</span> <span class="hljs-string">worker</span>
  <span class="hljs-attr">image:</span> <span class="hljs-string">kindest/node:v1.30.0</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">role:</span> <span class="hljs-string">worker</span>
  <span class="hljs-attr">image:</span> <span class="hljs-string">kindest/node:v1.30.0</span>
</code></pre>
<p>This gave me hands-on experience with managing a cluster that closely resembles a production environment with separate control plane and worker nodes.</p>
<h3 id="heading-argocd-and-gitops-implementation">ArgoCD and GitOps Implementation</h3>
<p><strong>ArgoCD Installation</strong>: Installing ArgoCD was my first deep dive into GitOps tooling. I learned how to create dedicated namespaces, patch services to expose them externally, and manage RBAC for secure access.</p>
<p><strong>GitOps Workflow</strong>: The most fascinating part was experiencing true GitOps in action. I configured ArgoCD to:</p>
<ul>
<li><p>Automatically sync applications from my GitHub repository</p>
</li>
<li><p>Monitor changes in the <code>k8s-specifications</code> folder</p>
</li>
<li><p>Apply updates to the cluster whenever I pushed changes to GitHub</p>
</li>
</ul>
<p><strong>Real-time Synchronization</strong>: I tested the GitOps functionality by changing replica counts directly in GitHub. Within minutes, ArgoCD detected the changes and automatically updated the cluster. Seeing pods scale up and down based on Git commits was incredibly satisfying and showed me the power of GitOps for production deployments.</p>
<h3 id="heading-microservices-architecture">Microservices Architecture</h3>
<p>The voting application consisted of multiple microservices:</p>
<ul>
<li><p><strong>Vote Service</strong> (Python) - Frontend for casting votes</p>
</li>
<li><p><strong>Result Service</strong> (Node.js) - Dashboard showing vote results</p>
</li>
<li><p><strong>Worker Service</strong> (.NET) - Processes votes from Redis to PostgreSQL</p>
</li>
<li><p><strong>Redis</strong> - Message queue for vote processing</p>
</li>
<li><p><strong>PostgreSQL</strong> - Database for storing vote results</p>
</li>
</ul>
<p>This project taught me how different technologies can work together seamlessly in a Kubernetes environment, with each service handling its specific responsibility.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755514931028/4472f606-f78a-4860-802e-56f944a51917.png" alt /></p>
<h3 id="heading-monitoring-with-prometheus-and-grafana">Monitoring with Prometheus and Grafana</h3>
<p>I also implemented a <strong>Prometheus-Grafana monitoring stack</strong> using Helm charts to monitor and visualize the voting application. This was my first hands-on experience with Helm charts in a real project, and it perfectly demonstrated why Helm is considered the package manager for Kubernetes.</p>
<p>I used the official Prometheus community Helm chart which automatically deployed Prometheus server, Alertmanager, and Grafana with pre-configured dashboards. Setting up the entire monitoring stack with a single <code>helm install</code> command was incredibly efficient compared to manually creating dozens of YAML files.</p>
<p>The Grafana dashboards provided real-time insights into cluster metrics, pod resource usage, and application performance. I could visualize CPU and memory consumption across all microservices, monitor the health of PostgreSQL and Redis, and track request rates to the vote and result services. This monitoring setup gave me a clear understanding of how the voting application was performing under load and helped me identify potential bottlenecks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755514950345/17c85d57-b432-4185-9c3a-550ea38ad52d.png" alt /></p>
<h2 id="heading-what-i-learned-from-these-projects">What I Learned from These Projects</h2>
<p><strong>Real-world Application Architecture</strong>: Both projects showed me how theoretical Kubernetes concepts translate into practical applications. Understanding how frontend services communicate with backend APIs, and how those APIs connect to databases, gave me a complete picture of modern application deployment.</p>
<p><strong>Security Best Practices</strong>: Working with secrets, RBAC, and service accounts taught me the importance of security in Kubernetes. I learned that proper access control and secret management aren't optional - they're fundamental requirements.</p>
<p><strong>GitOps Philosophy</strong>: The ArgoCD project introduced me to the GitOps approach, where Git becomes the single source of truth for infrastructure and applications. This paradigm shift from push-based to pull-based deployments feels much more reliable and auditable.</p>
<p><strong>Networking Understanding</strong>: Configuring services, ingress controllers, and port forwarding gave me practical experience with Kubernetes networking. I now understand how traffic flows within a cluster and how to expose applications externally.</p>
<p><strong>Persistent Storage</strong>: Managing stateful applications like databases taught me about persistent volumes, storage classes, and the importance of data persistence in containerized environments.</p>
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p><strong>1️⃣ MiniKube Ingress Controller Issues</strong></p>
<p>Initially, the ingress controller wasn't routing traffic properly to my chat application. The frontend was accessible, but API calls to the backend were failing.</p>
<p><em>Solution</em>: I discovered that I needed to enable the MiniKube ingress addon with <code>minikube addons enable ingress</code> and ensure that the ingress resource was properly configured with the correct service names and ports.</p>
<p><strong>2️⃣ ArgoCD UI Access Problems</strong></p>
<p>After installing ArgoCD, I couldn't access the web interface even though the pods were running. The service was only accessible within the cluster.</p>
<p><em>Solution</em>: I had to patch the ArgoCD server service to change its type from <code>ClusterIP</code> to <code>NodePort</code>, then use port forwarding with the <code>--address 0.0.0.0</code> flag to make it accessible from my browser. I also had to add the appropriate inbound rules to the EC2 security group.</p>
<p><strong>3️⃣ Docker Permission Issues on EC2</strong></p>
<p>When setting up Kind on the EC2 instance, I kept getting "permission denied" errors when trying to run Docker commands.</p>
<p><em>Solution</em>: I needed to add the ubuntu user to the Docker group with <code>sudo usermod -aG docker ubuntu</code> and then refresh the group membership with <code>newgrp docker</code>. This allowed me to run Docker commands without sudo.</p>
<p><strong>4️⃣ JWT Token Authentication Issues in Chat Application</strong></p>
<p>Even after properly setting up the JWT secret in Kubernetes secrets, the frontend was continuously logging users out of the chat application. Users could register and login initially, but within seconds they would be automatically logged out, making the application unusable.</p>
<p><em>Solution</em>: I discovered that the issue was with how the JWT secret was being referenced in the backend deployment. The environment variable name in the deployment YAML had to exactly match what the backend was expecting. I also learned that the base64 encoded secret in Kubernetes gets automatically decoded when injected as an environment variable, so the backend was receiving the correct plaintext value.</p>
<h2 id="heading-resources-i-used">Resources I Used</h2>
<ol>
<li><p><a target="_blank" href="https://youtu.be/Y8oFew4MfqA?si=EEQv6qIiF8zHjw6v">TrainWithShubham | K8s ArgoCD Project</a></p>
</li>
<li><p><a target="_blank" href="https://kubernetes.io/docs/home/"><strong>Kubernetes Official Documentation</strong></a></p>
</li>
<li><p><a target="_blank" href="https://argo-cd.readthedocs.io/en/stable/"><strong>ArgoCD Documentation</strong></a></p>
</li>
</ol>
<h2 id="heading-lets-connect">Let's Connect!</h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>My LinkedIn</strong></a></p>
<p>🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I'd love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Kubernetes Deep Dive: From Auto Scaling to Service Mesh with Istio]]></title><description><![CDATA[Introduction
Hello readers 👋! Sorry for the delay with last week's article. Week 13 of my DevOps learning journey has been quite eventful. For the past two weeks, I've been diving deep into different Kubernetes concepts, and this week I continued on...]]></description><link>https://blog.akshanshsingh.com/kubernetes-deep-dive-from-auto-scaling-to-service-mesh-with-istio</link><guid isPermaLink="true">https://blog.akshanshsingh.com/kubernetes-deep-dive-from-auto-scaling-to-service-mesh-with-istio</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[Devops]]></category><category><![CDATA[learning]]></category><category><![CDATA[Learning Journey]]></category><category><![CDATA[Microservices]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Wed, 30 Jul 2025 04:09:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9cXMJHaViTM/upload/c076ed14d771ac0806b66a7e2af67127.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello readers 👋! Sorry for the delay with last week's article. Week 13 of my DevOps learning journey has been quite eventful. For the past two weeks, I've been diving deep into different Kubernetes concepts, and this week I continued on that path. After completing the fundamentals of Kubernetes last week, I covered some more advanced topics including Auto Scaling, Role-Based Access Control, Custom Resource Definitions, Helm, and Service Mesh with Istio.</p>
<h2 id="heading-auto-scaling-hpa-and-vpa">Auto Scaling (HPA and VPA)</h2>
<p>When I was learning about creating pods using manifest files, I discovered that we could scale the number of pods using the scale command like this: <code>kubectl scale deployment random-deployment -n random --replicas=3</code>. At that time, I thought scaling pods in Kubernetes was really straightforward, but as I learned more about production environments where application demands fluctuate throughout the day, I realized that manually scaling pods up or down isn't practical.</p>
<p>One of Kubernetes' main features is its ability to automatically scale resources according to demand and workload. Kubernetes provides two complementary autoscaling mechanisms: <strong>HPA</strong> and <strong>VPA</strong>.</p>
<p><strong>Horizontal Pod Autoscaling (HPA)</strong> works by having the HPA controller automatically scale the number of pod replicas in a Deployment, ReplicaSet, or StatefulSet based on observed metrics like CPU utilization, memory usage, or custom metrics. I learned how to create HPA manifest files and tested them in practice. Some common use cases for HPA that I discovered include:</p>
<ul>
<li><p><strong>Web applications</strong> with varying traffic patterns</p>
</li>
<li><p><strong>API services</strong> experiencing fluctuating request loads</p>
</li>
<li><p><strong>Processing workloads</strong> with queue-based scaling</p>
</li>
</ul>
<p><strong>Vertical Pod Autoscaling (VPA)</strong> automatically adjusts the CPU and memory requests/limits for containers in a pod based on historical and current resource usage patterns. VPA consists of three components:</p>
<ol>
<li><p><strong>Recommender</strong>: Analyzes resource usage and provides recommendations</p>
</li>
<li><p><strong>Updater</strong>: Decides which pods need updates and triggers eviction</p>
</li>
<li><p><strong>Admission Controller</strong>: Applies recommended resources to new/restarted pods</p>
</li>
</ol>
<p>Some use cases for VPA include:</p>
<ul>
<li><p><strong>Batch processing jobs</strong> with unpredictable resource needs</p>
</li>
<li><p><strong>Applications</strong> with evolving resource requirements over time</p>
</li>
<li><p><strong>Cost optimization</strong> by eliminating resource over-provisioning</p>
</li>
</ul>
<p>In summary, HPA increases the number of pods based on resource utilization, whereas VPA increases or decreases the resource limits of containers.</p>
<h2 id="heading-role-based-access-control-rbac">Role-Based Access Control (RBAC)</h2>
<p>In an organization using Kubernetes, there can be many users who need to work on different aspects of the platform. Each user may have different roles and responsibilities. To manage all these users and service accounts so they don't accidentally or intentionally cause trouble with the cluster and deployments, <strong>Role-Based Access Control</strong> is used. Without proper access controls, any user could potentially delete critical workloads, access secrets, or modify cluster configurations.</p>
<p>RBAC consists of three core components:</p>
<ul>
<li><p><strong>Subjects</strong>: Who is requesting access (Users, Groups, ServiceAccounts)</p>
</li>
<li><p><strong>Resources</strong>: What they want to access (Pods, Services, Secrets, etc.)</p>
</li>
<li><p><strong>Verbs</strong>: What actions they want to perform (get, list, create, delete, etc.)</p>
</li>
</ul>
<p>To create RBAC rules, we first need to create <strong>Roles</strong> or <strong>ClusterRoles</strong>. A Role defines permissions within a specific namespace, whereas a ClusterRole defines permissions across the entire cluster. After defining the rules for resources and what actions can be performed on those resources, RoleBinding and ClusterRoleBinding are created to define which subjects these rules will be applied to.</p>
<p>For example:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">kind:</span> <span class="hljs-string">Role</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">rbac.authorization.k8s.io/v1</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">apache-manager</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">apache</span>
<span class="hljs-attr">rules:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">apiGroups:</span> [<span class="hljs-string">"*"</span>]
    <span class="hljs-attr">resources:</span> [<span class="hljs-string">"deployments"</span>, <span class="hljs-string">"pods"</span>, <span class="hljs-string">"services"</span>]
    <span class="hljs-attr">verbs:</span> [<span class="hljs-string">"get"</span>, <span class="hljs-string">"apply"</span>, <span class="hljs-string">"delete"</span>, <span class="hljs-string">"watch"</span>, <span class="hljs-string">"create"</span>, <span class="hljs-string">"patch"</span>]
</code></pre>
<pre><code class="lang-yaml"><span class="hljs-attr">kind:</span> <span class="hljs-string">RoleBinding</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">rbac.authorization.k8s.io/v1</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">apache-manager-role-binding</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">apache</span>

<span class="hljs-attr">subjects:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">kind:</span> <span class="hljs-string">User</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">apache-user</span>
    <span class="hljs-attr">namespace:</span> <span class="hljs-string">rbac.authorization.k8s.io</span>

<span class="hljs-attr">roleRef:</span>
  <span class="hljs-attr">kind:</span> <span class="hljs-string">Role</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">apache-manager</span>
  <span class="hljs-attr">apiGroup:</span> <span class="hljs-string">rbac.authorization.k8s.io</span>
</code></pre>
<p>I also learned about important commands such as <code>kubectl auth can-i get pods -n apache --as=&lt;user&gt;</code> to check whether a user has permission to execute specified commands, which I found really useful while learning and testing. I also noted several best practices for RBAC policies, such as the principle of least privilege, namespace isolation, and service account strategy.</p>
<h2 id="heading-custom-resource-definitions-crds">Custom Resource Definitions (CRDs)</h2>
<p>Until now, I had been learning and experimenting with the built-in resources that Kubernetes provides, such as pods and services. But CRDs allow us to extend the Kubernetes API with our own custom resources. I can already imagine how useful CRDs can be as the complexity of modern applications grows rapidly. With CRDs, we can define application-specific resources that the Kubernetes API can manage natively. CRDs are essentially like custom data structures.</p>
<p>To create a CRD, we need to define the structure and validation rules of our custom resource. For example, I created a CRD for a simple database:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apiextensions.k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">CustomResourceDefinition</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">databases.example.com</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">group:</span> <span class="hljs-string">example.com</span>
  <span class="hljs-attr">versions:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">v1</span>
    <span class="hljs-attr">served:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">storage:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">schema:</span>
      <span class="hljs-attr">openAPIV3Schema:</span>
        <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
        <span class="hljs-attr">properties:</span>
          <span class="hljs-attr">spec:</span>
            <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
            <span class="hljs-attr">properties:</span>
              <span class="hljs-attr">engine:</span>
                <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
                <span class="hljs-attr">enum:</span> [<span class="hljs-string">"mysql"</span>, <span class="hljs-string">"postgres"</span>]
              <span class="hljs-attr">version:</span>
                <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">storage:</span>
                <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
            <span class="hljs-attr">required:</span> [<span class="hljs-string">"engine"</span>, <span class="hljs-string">"version"</span>]
          <span class="hljs-attr">status:</span>
            <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
            <span class="hljs-attr">properties:</span>
              <span class="hljs-attr">phase:</span>
                <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
  <span class="hljs-attr">scope:</span> <span class="hljs-string">Namespaced</span>
  <span class="hljs-attr">names:</span>
    <span class="hljs-attr">plural:</span> <span class="hljs-string">databases</span>
    <span class="hljs-attr">singular:</span> <span class="hljs-string">database</span>
    <span class="hljs-attr">kind:</span> <span class="hljs-string">Database</span>
</code></pre>
<p>After defining and applying this resource definition, we can use these resources in the same way as native Kubernetes resources and perform actions such as get, describe, etc.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">example.com/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Database</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">my-app-db</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">production</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">engine:</span> <span class="hljs-string">postgres</span>
  <span class="hljs-attr">version:</span> <span class="hljs-string">"1.4"</span>
  <span class="hljs-attr">storage:</span> <span class="hljs-string">"100Gi"</span>
</code></pre>
<h2 id="heading-helm">Helm</h2>
<p>I already knew that Kubernetes had multiple interconnected components, but what I didn't realize was just how many components there could be. So many that it can really become a hassle to create and manage all the YAML files for these components. This problem is solved by <strong>Helm</strong>. Helm addresses the critical problem of managing complex application deployments with multiple interconnected components. Instead of manually creating dozens of YAML files and managing their dependencies, Helm packages everything into reusable, versioned "charts." This idea immediately struck me as a genius solution, especially after seeing how lengthy and confusing these YAML files can become during my learning process.</p>
<h3 id="heading-helm-charts">Helm Charts</h3>
<p>A Helm chart is a collection of files that describe a related set of Kubernetes resources. I think of it like a recipe book - it contains all the instructions (templates) and ingredients (values) needed to create a complete meal (application deployment). I installed Helm on my EC2 instance using the Helm installation guide and observed the structure of a Helm chart.</p>
<p><strong>Chart Structure</strong>:</p>
<pre><code class="lang-plaintext">mychart/
├── Chart.yaml          # Chart metadata
├── values.yaml         # Default configuration values
├── templates/          # Kubernetes manifests templates
│   ├── deployment.yaml
│   ├── service.yaml
│   └── ingress.yaml
└── charts/            # Chart dependencies
</code></pre>
<p>The real power lies in templating - instead of static YAML files, Helm uses Go templates that dynamically generate manifests based on provided values.</p>
<p>We can either create a Helm chart from scratch or install charts from repositories that contain multiple charts. Chart repositories function like Docker registries - centralized locations for sharing and distributing packaged applications. Through these charts, we can manage multiple components for our Kubernetes cluster. The process followed for a Helm chart is as follows:</p>
<pre><code class="lang-plaintext">1. CREATE CHART
   ↓
   helm create myapp
   ↓
2. CUSTOMIZE TEMPLATES
   ↓
   Edit templates/*.yaml files
   Edit values.yaml
   ↓
3. VALIDATE &amp; TEST
   ↓
   helm lint ./myapp
   helm template myapp ./myapp --debug
   ↓
4. PACKAGE CHART
   ↓
   helm package ./myapp
   ↓
5. DEPLOY TO CLUSTER
   ↓
   helm install myrelease ./myapp
</code></pre>
<p>A chart is a bundle that contains all the necessary resources for an application. Helm provides versioning and rollback capabilities, which are essential for maintaining application stability. If an update causes issues, teams can easily revert to a previous stable state using the <code>helm rollback</code> command. This feature is particularly valuable in CI/CD pipelines, where automated deployments and rollbacks are critical.</p>
<h2 id="heading-service-mesh-istio">Service Mesh - Istio</h2>
<p>After getting familiar with Helm and gaining hands-on experience with it, I learned about a new challenge in microservices architecture: managing communication between dozens or hundreds of microservices. In complex microservices architectures, cross-cutting concerns like security, observability, and traffic management become scattered across application code. The traditional solutions to this problem were either application-level (embedding networking logic into each service) or network-level (using traditional load balancers and firewalls). However, these approaches aren't suitable for the modern era. The solution to these challenges is <strong>Service Mesh</strong>.</p>
<p>A <strong>Service Mesh</strong> is a dedicated infrastructure layer for managing communication between services in a microservice-based system. It provides a centralized, dedicated infrastructure layer that handles the intricacies of service-to-service communication. <strong>Istio</strong> is a popular open-source service mesh tool.</p>
<p>Istio has two main core components:</p>
<ol>
<li><p><strong>Data Plane - Envoy Sidecars</strong>: Istio injects Envoy proxy sidecars alongside each application container. These proxies intercept all network traffic, providing:</p>
<ul>
<li><p>Transparent service discovery</p>
</li>
<li><p>Load balancing and health checking</p>
</li>
<li><p>Security policy enforcement</p>
</li>
<li><p>Metrics collection and distributed tracing</p>
</li>
</ul>
</li>
<li><p><strong>Control Plane - Istiod</strong>: The unified control plane manages configuration and policy distribution:</p>
<ul>
<li><p><strong>Pilot</strong>: Service discovery and traffic management</p>
</li>
<li><p><strong>Citadel</strong>: Certificate authority for mTLS</p>
</li>
<li><p><strong>Galley</strong>: Configuration validation and distribution</p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753847888026/61c01be2-9b0f-48e8-a656-f59aa57cf3ea.png" alt class="image--center mx-auto" /></p>
<p>At first, it seemed as complicated as it sounds, but by slowly understanding the infrastructure and working with Istio to deploy a sample application, I gained some confidence. I installed Istio and after deploying the sample application, I learned to visualize the service mesh and network using the Kiali dashboard.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753847908233/d702c921-4485-4e13-bbbd-35548119f7a8.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-other-concepts">Other Concepts</h2>
<p>Apart from these major concepts, I also explored some other smaller but interesting and useful topics such as Node Affinity, Taints and Tolerations, Init containers, and Sidecar containers. I learned how these features contribute to the Kubernetes environment and did hands-on mini exercises for these services, like using Init containers for database readiness checks and sidecar containers for metric collection.</p>
<h2 id="heading-resources-i-used">Resources I used-</h2>
<ol>
<li><p><a target="_blank" href="https://kubernetes.io/docs/home/"><strong>Kubernetes Official Do</strong></a><a target="_blank" href="https://kubernetes.io/docs/home/"><strong>cs</strong></a></p>
</li>
<li><p><a target="_blank" href="https://kubernetes.io/docs/home/"><strong>Kubernetes | TrainWit</strong></a><a target="_blank" href="https://youtu.be/W04brGNgxN4?si=W5sXeOe2Erwq72of"><strong>hS</strong></a><a target="_blank" href="https://youtu.be/W04brGNgxN4?si=W5sXeOe2Erwq72of"><strong>hu</strong></a><a target="_blank" href="https://kubernetes.io/docs/home/"><strong>bham</strong></a></p>
</li>
<li><p><a target="_blank" href="https://istio.io/latest/docs/overview/what-is-istio/"><strong>Istio Documentation</strong></a></p>
</li>
</ol>
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p><strong>1️⃣ Service unavailable for K8s dashboard with Kind cluster</strong></p>
<p>This was quite frustrating initially as I couldn't access the Kubernetes dashboard that I had set up. The dashboard service wasn't accessible through the usual methods, and I spent some time troubleshooting network connectivity issues.</p>
<p><em>Solution</em>: I resolved this by using port forwarding with the command: <code>kubectl -n kubernetes-dashboard port-forward service/kubernetes-dashboard 8443:443 --address=0.0.0.0</code>. This allowed me to forward the dashboard service to my local machine and access it through the browser.</p>
<p><strong>2️⃣ Couldn't connect to Istio Kiali Dashboard</strong></p>
<p>After successfully installing Istio and deploying sample applications, I couldn't access the Kiali dashboard to visualize the service mesh. This was particularly challenging because the dashboard is crucial for understanding how services communicate within the mesh.</p>
<p><em>Solution</em>: I used local port forwarding by opening an SSH tunnel that forwards local port 20001 to the EC2's port 20001. This allowed me to securely access the Kiali dashboard running on my EC2 instance from my local machine.</p>
<h2 id="heading-whats-next">What's Next</h2>
<p>After covering these many topics and concepts about Kubernetes, I'm planning to work on a comprehensive project that uses all these concepts and involves different third-party components and services such as Prometheus and Grafana. This should help me consolidate my learning and gain practical experience with real-world scenarios.</p>
<h2 id="heading-lets-connect">Let's Connect!</h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>My LinkedIn</strong></a></p>
<p>🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I'd love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Mastering Kubernetes Core Concepts]]></title><description><![CDATA[Introduction
Hello there to all 👋! This week has been one of the most overwhelming ones yet. I have been studying and learning Kubernetes for the past 8-9 days, and I have to say it hasn't been easy. The amount of information one has to absorb while...]]></description><link>https://blog.akshanshsingh.com/mastering-kubernetes-core-concepts</link><guid isPermaLink="true">https://blog.akshanshsingh.com/mastering-kubernetes-core-concepts</guid><category><![CDATA[Devops]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[learning]]></category><category><![CDATA[Learning Journey]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sat, 19 Jul 2025 15:40:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752939505528/209e829a-c297-424e-9a76-2e25fd16acc0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there to all 👋! This week has been one of the most overwhelming ones yet. I have been studying and learning Kubernetes for the past 8-9 days, and I have to say it hasn't been easy. The amount of information one has to absorb while learning and understanding Kubernetes is truly overwhelming. Last week, I got started with Kubernetes and learned what Kubernetes is about, what problems it solves, and its architecture. This week I continued on that journey and learned many important concepts such as Namespaces, Pods, Deployments, Services, Jobs, storage, and more.</p>
<h2 id="heading-workload-resources">Workload Resources</h2>
<p>After going through and understanding the core concepts and architecture, I moved on to the next topic, which was Workload resources. Workload resources comprise Pods, Controllers, and Configuration management. Once again, to practice while learning, I created an EC2 instance of type t2.medium and learned to install Kubernetes through both Minikube and Kind. Once the K8s setup was done, I got started with the first topic, which was Namespaces.</p>
<p><code>Namespaces</code> are virtual clusters within a physical Kubernetes cluster. Namespaces are Kubernetes' way of organizing and isolating resources within a cluster.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752938751976/54638a2b-1a68-4590-a8fc-d07ced367644.png" alt class="image--center mx-auto" /></p>
<p>We know Kubernetes is a container orchestration tool, and all those containers are wrapped with an abstract layer called Pods.</p>
<p><code>Pods</code> are the fundamental building blocks of Kubernetes, serving as the smallest deployable unit that can be created and managed within the system. The purpose of pods is to wrap containers with shared networking and storage.</p>
<p>I came to know that pods are ephemeral, which means they can fail or be destroyed easily. So as part of K8s's auto-healing process, K8s uses controllers like Deployment to maintain the desired state and re-create or restart pods to fulfill the desired number of pods.</p>
<p><code>Deployment</code> manages multiple identical pods and ensures the desired number of pod replicas are running. The same functionality is provided by ReplicaSets, but Deployment has a few important advantages over it, such as rolling updates and rollbacks. Since these pods run inside the cluster, to access the applications running inside the pods, we use Services.</p>
<p><code>Service</code> allows for stable and permanent networking for pods, ensuring that pods remain accessible even as they are updated or scaled. Service has 4 types: ClusterIP (internal), NodePort (external), LoadBalancer (cloud), and ExternalName.</p>
<p>While learning and practicing these concepts, I was creating these resources using commands, and then I came to know about manifest files. Manifest files are YAML or JSON files that describe the desired state of resources such as Pods, Deployments, and Services, and can be applied directly using the kubectl tool. This approach was much more efficient than using commands to create, update, or delete resources. Examples of all the manifest files for different resources are well documented in the Kubernetes official documentation, which has been a great help.</p>
<h2 id="heading-workload-controllers">Workload Controllers</h2>
<p>Like Deployment and ReplicaSets, there are more controllers that ensure the state of K8s is equal to the desired state, such as StatefulSet and DaemonSet.</p>
<p><code>StatefulSet</code> manages stateful applications that need stable identities and persistent storage, such as databases, message queues, etc. Unlike Deployments, which are used for stateless applications, StatefulSets ensure that each Pod has a unique, persistent identity, including a stable hostname and volume.</p>
<p><code>DaemonSet</code> ensures exactly one pod runs on every node (or selected nodes). DaemonSets are perfect for system-level services that need to run on every node, such as log collectors, monitoring agents, etc.</p>
<p>While these controllers are used to ensure the pods are running on the desired worker nodes and in the desired number, <code>Jobs</code> and <code>CronJobs</code> handle workloads that need to run to completion rather than continuously. While Deployments and StatefulSets keep applications running forever, Jobs are designed to run to completion and then stop. Jobs are perfect for one-time tasks, batch processing, and migration tasks. While Jobs run to completion for a single time, CronJobs run on a schedule. These can be used for scheduled maintenance, periodic backups, and regular data processing. I practiced creating Jobs and CronJobs by creating a simple CronJob to log a sentence.</p>
<h2 id="heading-storage-resources">Storage Resources</h2>
<p>I have learned that Pods are ephemeral, which means if or when they die, their data disappears. But for stateful applications like databases, any team or company cannot afford to lose their data. So, the solution to this problem is Persistent Volume and Persistent Volume Claim, which provides storage that outlives individual pods.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752938779843/2b12142b-67d5-41c4-b604-c702272ec8be.png" alt class="image--center mx-auto" /></p>
<p><code>Persistent Volume</code> is a piece of storage in the cluster that has been provisioned by the administrator or dynamically provisioned. It represents actual storage like disk space or cloud storage, and this storage is not dependent on any pod.</p>
<p><code>Persistent Volume Claim</code> is the request to use storage by an application. When an application requests storage (Persistent Volume), the volume binds to the application. The process of binding is as follows:</p>
<ol>
<li><p><strong>Administrator provisions PV</strong> (or dynamic provisioning creates it)</p>
</li>
<li><p><strong>User creates PVC</strong> specifying storage requirements</p>
</li>
<li><p><strong>Kubernetes matches PVC to suitable PV</strong> (binding process)</p>
</li>
<li><p><strong>Pod uses PVC</strong> to mount persistent storage</p>
</li>
<li><p><strong>Data persists</strong> even if pod is deleted</p>
</li>
</ol>
<h2 id="heading-networking-ingress">Networking - Ingress</h2>
<p>Up to this point, I learned about internal networking for pods and how to access them from inside the container. But when deploying an application, we want users to be able to access and route through the application without any errors. For that purpose, Kubernetes <code>Ingress</code> is used to provide a centralized way to manage external access to services within a cluster. It allows for the routing of HTTP and HTTPS traffic to different services based on criteria such as URL paths and hostnames. Ingress is an important and essential part of the Kubernetes ecosystem.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752938810360/4b00e399-a239-4efc-a92b-6a5a5929a153.png" alt class="image--center mx-auto" /></p>
<p>Ingress comprises 3 main components:</p>
<ol>
<li><p><strong>Ingress Resource</strong>: The configuration object defining routing rules</p>
</li>
<li><p><strong>Ingress Controller</strong>: The actual implementation that processes Ingress rules (nginx, Traefik, AWS ALB, etc.)</p>
</li>
<li><p><strong>Backend Services</strong>: The destination services that receive routed traffic</p>
</li>
</ol>
<p>Ingress has different routing strategies, such as path-based routing like /api, /app, etc., and hostname-based routing such as <a target="_blank" href="http://api.company.com">api.company.com</a> and <a target="_blank" href="http://blog.company.com">blog.company.com</a>. Ingress is a complex and deep topic, so even though I learned to configure and implement Ingress rules in demo applications, I still need to dive deeper into this topic in the future.</p>
<h2 id="heading-resource-configuration">Resource Configuration</h2>
<p>So far, I had learned the fundamental yet important topics of K8s such as storage, networking, etc., but learning about resource configuration is as important as them. Resource configuration consists of concepts like ConfigMaps, Secrets, Resource Quotas, Limits, and much more. But for initial understanding, I decided to focus on these four first. By creating multiple manifest files for the creation and deletion of resources like pods, deployments, and services, I discovered that configuration should be stored in a separate environment. Just like we use .env to store configurations and secrets of the application, in K8s we use ConfigMaps and Secrets.</p>
<p><code>ConfigMap</code> stores configuration data as key-value pairs that pods can consume as environment variables, command-line arguments, or mounted files. ConfigMap stores non-sensitive data like database URLs, settings, etc.</p>
<p><code>Secrets</code> store sensitive data like passwords, tokens, and keys. They're similar to ConfigMaps but with additional security features. Data in Secrets configuration is usually stored in base64 format to encode binary data into text format for systems that can't handle binary data well.</p>
<p>These two are used to manage configuration data and sensitive information, whereas Resource Quotas and Limits are part of a resource management strategy that ensures fair distribution of resources. Resource Quotas and Limits work together to control how much CPU, memory, and other resources can be consumed at both the namespace and pod levels.</p>
<p>These are used to set maximum resources a container can use. If exceeded, the container is throttled (CPU) or killed (memory). Managing resources inside the cluster is critical to ensure that applications run smoothly while simultaneously optimizing costs.</p>
<h2 id="heading-resources-i-used">Resources I Used</h2>
<ol>
<li><p><a target="_blank" href="https://kubernetes.io/docs/home/"><strong>Kubernetes Official Docs</strong></a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/W04brGNgxN4?si=W5sXeOe2Erwq72of"><strong>Kubernetes | TrainWithShubham</strong></a></p>
</li>
</ol>
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p><strong>1️⃣ K8s pod's status - CrashLoopBackoff when creating deployment</strong></p>
<p>This was frustrating because the pods kept restarting in an endless loop. After debugging for a while, I discovered that I was working on the wrong Git branch, which had different configuration files than what I expected. The pod was trying to run with incorrect configurations, causing it to crash repeatedly.</p>
<p><em>Solution</em>: Switched to the correct Git branch with the proper configuration files, and the deployment worked perfectly.</p>
<p><strong>2️⃣ Unexpected Ingress error - Validating Admission Webhook for the NGINX Ingress Controller</strong></p>
<p>This error appeared when I was trying to create Ingress resources. The webhook was rejecting my Ingress configurations, and despite trying various troubleshooting approaches like checking the webhook configuration and validating my manifest files, I couldn't resolve the issue.</p>
<p><em>Solution</em>: After spending considerable time debugging, I decided to create a fresh cluster, which resolved the issue completely.</p>
<p><strong>3️⃣ Wasn't able to update previously written manifest files</strong></p>
<p>When trying to edit YAML files using vim, I kept getting permission denied errors. This was particularly annoying when I needed to make quick changes to my configurations during testing.</p>
<p><em>Solution</em>: Had to use sudo with the vim command to get the necessary permissions to edit the files.</p>
<h2 id="heading-whats-next">What's Next</h2>
<p>The next topics for me in Kubernetes are Auto-scaling (HPA and VPA) and Taints and Tolerations, so I will continue with my Kubernetes learning journey.</p>
<h2 id="heading-lets-connect">Let's Connect!</h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>My LinkedIn</strong></a></p>
<p>🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I'd love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Hands-On Docker Projects and Kubernetes Basics]]></title><description><![CDATA[Introduction
Hello there👋! This past week was both exciting and intense. After understanding Docker, I wanted to explore it more practically, so I decided to create a couple of mini projects. I also got started with Kubernetes, and to say it's confu...]]></description><link>https://blog.akshanshsingh.com/hands-on-docker-projects-and-kubernetes-basics</link><guid isPermaLink="true">https://blog.akshanshsingh.com/hands-on-docker-projects-and-kubernetes-basics</guid><category><![CDATA[Devops]]></category><category><![CDATA[learning]]></category><category><![CDATA[Learning Journey]]></category><category><![CDATA[#learning-in-public]]></category><category><![CDATA[Docker]]></category><category><![CDATA[deployment]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sun, 13 Jul 2025 17:35:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752428072721/9c61e9e5-7a21-44a1-b65d-dfc05a7ede20.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there👋! This past week was both exciting and intense. After understanding Docker, I wanted to explore it more practically, so I decided to create a couple of mini projects. I also got started with Kubernetes, and to say it's confusing at first would be an understatement. In this article, I'll talk about my experience with the Docker projects and my first impressions of Kubernetes.</p>
<h2 id="heading-mini-project-1-web-app-with-nginx-mysql">Mini Project 1: Web App with Nginx + MySQL</h2>
<p>After getting the hang of Docker and its different components and concepts, I was ready to experiment by implementing what I learned to deploy something real. I decided to choose a simple Notes application with CRUD operations using Django for the backend, Nginx as a proxy, and MySQL as the database. I started with an EC2 instance and installed Docker and Docker Compose. Then I cloned the selected repository into the EC2 instance.</p>
<p>The repository was divided into frontend, backend, and nginx sections, and it had pre-existing Dockerfiles which I double-checked for reference. I created a fresh docker-compose.yml file with 3 services: Nginx, MySQL, and Django.</p>
<p>Here, the Nginx service depends on Django, and Django depends on the database service since the database needs to initialize first. For each service, I configured the ports, network, container name, and build image. Since the project had Django and MySQL, to connect Django and MySQL, we need to use the migrate command to create the database and tables, and Gunicorn is used to serve the Django application. All the database credentials were passed through the environment file.</p>
<p>To ensure proper initialization of services and proper connection, I used health checks in both the database service and Django app service. I had some problems with the containers not connecting to each other due to networking issues, but after some troubleshooting, I was able to initialize and connect the services properly.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752426905585/bc7f2fca-fef3-4be4-8c50-720e568bf1e9.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752426928523/25522016-5610-4499-9575-ed57627cc17e.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-mini-project-2-spring-boot-application">Mini Project 2: Spring Boot Application</h2>
<p>As part of my second mini project, I chose a Spring Boot application containing 3 components: Thymeleaf (UI), Spring Boot (backend), and MySQL (database), with Maven as the build tool. In the Dockerfile, I chose to go with a multi-stage build - the first stage to install all dependencies and build the application as an artifact, and the second stage with a smaller base image to run the application.</p>
<p>After completing the Dockerfile, it was time to configure the docker-compose file. This project had two main services: the main application and the database (MySQL). I followed the same process as the previous project - configuring container name, base image, ports, creating a separate network and volume, and setting up health checks to ensure proper initialization and connection.</p>
<p>The difference was in configuring environment variables. Using the <code>application.properties</code> file, I noted all the required parameters and provided them in the docker-compose file using the <code>environment</code> object. After some trial and error, I got the containers running and checked the application on the instance's public IP.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752426986076/df480067-a8d2-40d1-98cd-706aabcc1ab4.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-getting-started-with-kubernetes">Getting Started with Kubernetes</h2>
<p>After completing the projects using Docker, it was time to start something new. After Docker, I decided to start learning one of the most important tools in the DevOps field - Kubernetes. Kubernetes sits at the heart of modern cloud-native application deployment and management.</p>
<p>I started with "What is Kubernetes?" The answer I found through Kubernetes official documentation is that <strong>Kubernetes</strong> (often abbreviated as "K8s") is an open-source <strong>container orchestration platform</strong> that automates the deployment, scaling, and management of containerized applications. It's like the "operating system for the cloud" - just as your computer's OS manages programs and resources, Kubernetes manages containers and compute resources across multiple machines.</p>
<p>Then I wanted to know what problems Kubernetes actually solves. K8s solves problems like:</p>
<ol>
<li><p>Manual scaling</p>
</li>
<li><p>Service discovery</p>
</li>
<li><p>Load distribution</p>
</li>
<li><p>Health monitoring</p>
</li>
<li><p>Resource optimization</p>
</li>
</ol>
<p>While solving all of these critical problems, K8s also delivers concrete business value such as faster release cycles, cost efficiency, reliability, high scalability, and developer productivity. With the rise of containers, the moving trend from monolith to microservices, and the rising demand to manage hundreds of containers, container orchestration tools like Kubernetes have become an essential part of the software development and deployment lifecycle.</p>
<h3 id="heading-k8s-architecture">K8s Architecture</h3>
<p>Understanding the Kubernetes architecture is essential as it provides the fundamental framework for managing containerized applications effectively. Kubernetes follows a <strong>master-worker pattern</strong> (also called control plane and data plane).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752426998966/a3790668-7595-4309-a936-11dd4dcdb0d5.png" alt class="image--center mx-auto" /></p>
<p>The key components of a Kubernetes cluster are:</p>
<ul>
<li><p><strong>Pod</strong>: The smallest deployable unit in Kubernetes, grouping one or more containers that share storage, network, and a specification.</p>
</li>
<li><p><strong>kube-api-server</strong>: The central "front door" that receives and processes all REST requests for the cluster.</p>
</li>
<li><p><strong>etcd</strong>: A lightweight, distributed key-value store that persistently holds all cluster configuration and state.</p>
</li>
<li><p><strong>kube-scheduler</strong>: Watches for new pods with no assigned node and assigns them to the most appropriate node.</p>
</li>
<li><p><strong>kube-controller-manager</strong>: Runs background controllers (like replication and endpoint controllers) to ensure the cluster's desired state matches the actual state.</p>
</li>
<li><p><strong>cloud-controller-manager</strong>: Integrates Kubernetes with your cloud provider's API to manage cloud-specific resources (e.g., load balancers, volumes).</p>
</li>
<li><p><strong>kubelet</strong>: An agent running on each node that ensures containers described in PodSpecs are up and healthy.</p>
</li>
<li><p><strong>kube-proxy</strong>: Maintains network rules on nodes to allow communication to your pods from inside or outside the cluster.</p>
</li>
<li><p><strong>kubectl</strong>: The command-line tool used to send commands to the kube-api-server and manage your cluster.</p>
</li>
</ul>
<p>The architecture follows a <strong>declarative workflow</strong>:</p>
<ol>
<li><p><strong>You submit a request</strong> (via kubectl) → API Server receives it</p>
</li>
<li><p><strong>API Server validates and stores</strong> → Information goes to etcd</p>
</li>
<li><p><strong>Scheduler assigns work</strong> → Decides which node should run the pod</p>
</li>
<li><p><strong>kubelet executes</strong> → Node agent creates and manages containers</p>
</li>
<li><p><strong>Controllers monitor</strong> → Ensure everything stays as desired</p>
</li>
<li><p><strong>kube-proxy handles networking</strong> → Manages traffic routing</p>
</li>
</ol>
<p>Through this, I understood how the components work together. I also learned about different installation methods for Kubernetes such as Minikube, Kubeadm, and KinD. As I got to know more about K8s, the more confusing it became for me, and I expected that since Kubernetes is not easy to learn and is a big and complex tool. But slowly and steadily, I hope I can learn K8s effectively and use it for practical and real-world implementations.</p>
<h2 id="heading-resources-i-used">Resources I Used</h2>
<ol>
<li><p><a target="_blank" href="https://youtu.be/s_o8dwzRlu4?si=rlt-a5LMw5mLbMmq">Kubernetes Crash Course | Techworld with Nana</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/W04brGNgxN4?si=W5sXeOe2Erwq72of">Kubernetes | TrainWithShubham</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/9bSbNNH4Nqw?si=DKdplEJVeGdrheDW">Docker | TrainWithShubham</a></p>
</li>
<li><p><a target="_blank" href="https://kubernetes.io/docs/home/">Kubernetes Official Docs</a></p>
</li>
</ol>
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p><strong>1️⃣ Containers couldn't connect to network</strong></p>
<p>This was frustrating because the containers were running individually, but they couldn't communicate with each other. I spent quite some time debugging this issue before realizing the root cause.</p>
<p><em>Solution:</em> I hadn't configured the network properly between the services in the docker-compose file. I needed to explicitly define a custom network and ensure all services were part of the same network to enable inter-container communication.</p>
<p><strong>2️⃣ Application redirecting to Nginx welcome page instead of the notes app</strong></p>
<p>When I opened the application on port 80, it kept showing the default Nginx welcome page instead of my notes application. This was confusing because the containers seemed to be running fine.</p>
<p><em>Solution:</em> The issue was in the Nginx configuration. I had to change the container name to match the service name in the default.conf file in Nginx. This allowed Nginx to properly proxy requests to the Django application container.</p>
<p><strong>3️⃣ Difficulty understanding the key components of K8s and its flow</strong></p>
<p>Kubernetes felt overwhelming at first. There are so many components and concepts, and understanding how they all work together was challenging. The official documentation, while comprehensive, felt too technical for a beginner.</p>
<p><em>Solution:</em> I referred to a Kubernetes crash course video to better understand the big picture and components. Visual explanations and practical examples helped me grasp the concepts much better than just reading documentation.</p>
<h2 id="heading-whats-next">What's Next?</h2>
<p>As I said, Kubernetes is a complex and difficult tool to master, so I will continue to learn and understand the basics first and build a strong foundation before moving on to advanced concepts. I plan to set up a local Kubernetes cluster and deploy some simple applications to get hands-on experience.</p>
<h2 id="heading-lets-connect">Let's Connect!</h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>My LinkedIn</strong></a> 🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I'd love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Python Automation Scripts & Multi-Container Docker Applications]]></title><description><![CDATA[Introduction
Hello there! I was unable to write any article for the past 2 weeks due to a few reasons, but the learning process didn't stop. For the past two weeks, I have been revising and exploring the capabilities of Python and understanding Docke...]]></description><link>https://blog.akshanshsingh.com/python-automation-scripts-and-multi-container-docker-applications</link><guid isPermaLink="true">https://blog.akshanshsingh.com/python-automation-scripts-and-multi-container-docker-applications</guid><category><![CDATA[Docker]]></category><category><![CDATA[Devops]]></category><category><![CDATA[learning]]></category><category><![CDATA[#learning-in-public]]></category><category><![CDATA[Python]]></category><category><![CDATA[boto3]]></category><category><![CDATA[containers]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sat, 28 Jun 2025 11:07:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751108759996/a2f73403-fee0-4a46-b3d1-645c8c5657fb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! I was unable to write any article for the past 2 weeks due to a few reasons, but the learning process didn't stop. For the past two weeks, I have been revising and exploring the capabilities of Python and understanding Docker in a more comprehensive way, which is one of the most important tools in the modern software development era. So in this article, I will be discussing the experiments I have been doing with Python and my experience learning Docker.</p>
<h2 id="heading-python-revision-and-scripting">Python Revision and Scripting</h2>
<p>Python is widely used in DevOps due to its versatility. It is used for automation, CI/CD pipelines, infrastructure as code (IaC), and more. One of the most common applications of Python is scripting, and the extensive library support makes Python an easy choice for engineers when it comes to automation.</p>
<p>In my first semester, Python was part of our curriculum, but it wasn't taught extensively. So first, I revised the basic syntax and fundamental concepts of Python such as lists, sets, dictionaries, functions, etc., and practiced them using simple programs.</p>
<p>After revising the basic syntax and concepts, it was time to learn important stuff like modules, automation, and scripting. The libraries I learned about that are really important and useful in scripting are <code>os</code>, <code>subprocess</code>, and <code>argparse</code>. These modules are essential for automating Linux system tasks. I learned different functions of these modules such as <code>os.system()</code>, <code>os.mkdir()</code>, <a target="_blank" href="http://subprocess.run"><code>subprocess.run</code></a><code>([])</code>, etc. To implement these functions in a real-world script, I created an Ubuntu VM and wrote a user management script to perform addition and removal of users and groups.</p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>

<span class="hljs-keyword">import</span> argparse
<span class="hljs-keyword">import</span> subprocess
<span class="hljs-keyword">import</span> logging
<span class="hljs-keyword">import</span> getpass

logging.basicConfig(
    filename=<span class="hljs-string">"logs/actions.log"</span>,
    level=logging.INFO,
    format=<span class="hljs-string">"%(asctime)s - %(levelname)s - %(message)s"</span>
)

<span class="hljs-comment"># Main command runner</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_cmd</span>(<span class="hljs-params">cmd</span>):</span>
    <span class="hljs-keyword">try</span>:
        result = subprocess.run(cmd, check=<span class="hljs-literal">True</span>, text=<span class="hljs-literal">True</span>, capture_output=<span class="hljs-literal">True</span>)
        logging.info(<span class="hljs-string">f"Command succeeded: <span class="hljs-subst">{<span class="hljs-string">' '</span>.join(cmd)}</span>"</span>)
        print(result.stdout.strip())
    <span class="hljs-keyword">except</span> subprocess.CalledProcessError <span class="hljs-keyword">as</span> e:
        logging.error(<span class="hljs-string">f"Command failed: <span class="hljs-subst">{<span class="hljs-string">' '</span>.join(cmd)}</span>\n<span class="hljs-subst">{e.stderr}</span>"</span>)
        print(<span class="hljs-string">f"Error: <span class="hljs-subst">{e.stderr.strip()}</span>"</span>)

<span class="hljs-comment"># Argument parser</span>
parser = argparse.ArgumentParser(description=<span class="hljs-string">"Linux User &amp; Group Management"</span>)

parser.add_argument(<span class="hljs-string">'--add-user'</span>, help=<span class="hljs-string">"Add a new user"</span>)
parser.add_argument(<span class="hljs-string">'--group'</span>, help=<span class="hljs-string">"Assign user to group (with --add-user)"</span>)
parser.add_argument(<span class="hljs-string">'--del-user'</span>, help=<span class="hljs-string">"Delete a user"</span>)
parser.add_argument(<span class="hljs-string">'--add-group'</span>, help=<span class="hljs-string">"Create a new group"</span>)
parser.add_argument(<span class="hljs-string">'--del-group'</span>, help=<span class="hljs-string">"Delete a group"</span>)
parser.add_argument(<span class="hljs-string">'--list-users'</span>, action=<span class="hljs-string">'store_true'</span>, help=<span class="hljs-string">"List all system users"</span>)
parser.add_argument(<span class="hljs-string">'--change-pass'</span>, help=<span class="hljs-string">"Change password of a user"</span>)

args = parser.parse_args()

<span class="hljs-comment"># Actions</span>
<span class="hljs-keyword">if</span> args.add_user:
    cmd = [<span class="hljs-string">"sudo"</span>, <span class="hljs-string">"useradd"</span>, args.add_user]
    <span class="hljs-keyword">if</span> args.group:
        cmd.extend([<span class="hljs-string">"-G"</span>, args.group])
    run_cmd(cmd)

<span class="hljs-keyword">if</span> args.del_user:
    run_cmd([<span class="hljs-string">"sudo"</span>, <span class="hljs-string">"userdel"</span>, <span class="hljs-string">"-r"</span>, args.del_user])

<span class="hljs-keyword">if</span> args.add_group:
    run_cmd([<span class="hljs-string">"sudo"</span>, <span class="hljs-string">"groupadd"</span>, args.add_group])

<span class="hljs-keyword">if</span> args.del_group:
    run_cmd([<span class="hljs-string">"sudo"</span>, <span class="hljs-string">"groupdel"</span>, args.del_group])

<span class="hljs-keyword">if</span> args.list_users:
    run_cmd([<span class="hljs-string">"cut"</span>, <span class="hljs-string">"-d:"</span>, <span class="hljs-string">"-f1"</span>, <span class="hljs-string">"/etc/passwd"</span>])

<span class="hljs-keyword">if</span> args.change_pass:
    password = getpass.getpass(<span class="hljs-string">"Enter new password: "</span>)
    confirm = getpass.getpass(<span class="hljs-string">"Confirm new password: "</span>)
    <span class="hljs-keyword">if</span> password == confirm:
        proc = subprocess.Popen([<span class="hljs-string">"sudo"</span>, <span class="hljs-string">"passwd"</span>, args.change_pass], stdin=subprocess.PIPE)
        proc.communicate(input=<span class="hljs-string">f"<span class="hljs-subst">{password}</span>\n<span class="hljs-subst">{password}</span>\n"</span>.encode())
        logging.info(<span class="hljs-string">f"Password changed for <span class="hljs-subst">{args.change_pass}</span>"</span>)
    <span class="hljs-keyword">else</span>:
        print(<span class="hljs-string">"Passwords do not match."</span>)
        logging.warning(<span class="hljs-string">f"Password mismatch for user <span class="hljs-subst">{args.change_pass}</span>"</span>)

<span class="hljs-comment"># Help command if no arguments are passed</span>
<span class="hljs-keyword">if</span> len(vars(args)) == <span class="hljs-number">0</span>:
    parser.print_help()
</code></pre>
<p>With the help of ChatGPT, I enhanced the script using the <code>getpass</code> module for the change password action, and it was working as expected.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751107676222/dc3befa0-9787-4240-a13e-fe3933c0b75a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-python-automation">Python Automation</h2>
<p>One of the main use cases of Python in DevOps is <strong>automation</strong>. I came to know about two libraries that are primarily used for automation: <strong>Boto3</strong> and <strong>Fabric</strong>. Boto3 is the official SDK that is used to interact with AWS services and simplifies the process of creating, deleting, and configuring different AWS services. While learning how to use Boto3, it became very clear to me that to make use of boto3 or even any automation tool, we first need to fully understand the manual process that we are trying to automate. So the knowledge of creating EC2 instances, uploading files to S3 buckets, and creating RDS instances using the AWS console with all the steps was crucial in order to write automation scripts using Boto3.</p>
<p>Using the Boto3 documentation, I created a few scripts to create EC2 instances, upload files to S3, and perform health checks on running EC2 instances. Understanding the responses of each call like <code>ec2.describe_instances()</code> was tricky at first as there was so much information to first understand and then filter out for what you actually want, such as instance ID and status. Formatting the responses using the <code>pprint</code> library helped in this process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751107701540/d1cdaa62-c7d4-413c-9624-21eeb6d43a42.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751107709313/789f5b3b-be28-4c64-9ccd-bfe1824ccd62.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-docker-deep-dive">Docker Deep Dive</h2>
<p>Earlier, to learn and work with different technologies like Jenkins and AWS, I learned about Docker but not in depth. But for DevOps, saying Docker is an essential tool would be an understatement, so learning Docker extensively is a must. So first, I checked what the main topics to learn Docker were, and Claude provided me with a list:</p>
<ul>
<li><p>Docker Overview (bigger picture)</p>
</li>
<li><p>Docker Architecture</p>
</li>
<li><p>Images</p>
</li>
<li><p>Containers</p>
</li>
<li><p>Dockerfile</p>
</li>
<li><p>Docker Networking</p>
</li>
<li><p>Volumes and Storage</p>
</li>
<li><p>Docker Compose</p>
</li>
<li><p>Docker Registry</p>
</li>
</ul>
<p><strong>Docker</strong> solves the "But it works on my machine" problem that was repeated millions of times in the past. The main reason for this problem is <strong>inconsistencies in development environments</strong> such as differences in operating systems, application dependency issues, etc. To overcome this issue, <strong>containerization</strong> is used—a lightweight form of virtualization that packages an application and all its dependencies into a portable, executable unit called a <strong>container</strong>.</p>
<p>Docker operates on a <strong>client-server architecture</strong> with three primary components:</p>
<ol>
<li><p>Docker Engine</p>
</li>
<li><p>Docker Client</p>
</li>
<li><p>Docker Registry</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751107882965/5ff48b98-4ef4-44c3-aa44-e532ca7adc4b.png" alt class="image--center mx-auto" /></p>
<p>I learned in-depth about important terminologies like Dockerfile, Images, and Containers. I also learned about the flow of Docker: <strong>Dockerfile</strong> is used to build read-only templates which are called <strong>Images</strong> that contain everything needed to run the application. These images are used to create <strong>Containers</strong> in which applications run.</p>
<p>I practiced Docker on an EC2 instance by cloning a few simple projects and trying to containerize them. I wrote Dockerfiles for different projects such as Java applications and Python applications—getting base images, creating working directories, copying source code, and installing dependencies. But the main challenge was when I tried to create a Dockerfile for my own Node project. When I was able to build its image successfully and deploy its container and could access my project, I was delighted.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751107922993/07036d8e-a6cd-479c-9bfa-04aebb85a0fc.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751107932223/c984c00d-3641-4b0e-862d-b01b863a4e02.png" alt class="image--center mx-auto" /></p>
<p>I proceeded to learn more important concepts such as networking in Docker, how Docker containers communicate with each other and with external networks using network drivers such as Bridge, Host, Overlay, and None network. After deploying a container for any project, when I was trying to restart the container, the data was being lost from the application, and then I came to know about the importance of Volumes and Storage. Volumes and Storage solve the challenge of data persistence in containerized applications. By creating and mounting the containers to named volumes, even if we stop, remove, or restart the container, the data will be stored in the attached volume.</p>
<p>While learning these topics, I noticed one thing: this is a lot of manual work for such simple projects—pulling images, creating Dockerfiles, building application images, running containers, all actions through manual commands. While commands are great for understanding the fundamental work, for real work at companies, this would be too time-consuming to configure hundreds of containers. The solution to this problem is <code>Docker Compose</code>. Docker Compose is a tool for defining and running multi-container Docker applications using YAML configuration files. I learned about the syntax and different components of the docker-compose.yml file such as services, networks, and volumes. To make use of it, I first removed all the containers from the previous projects and then configured a docker-compose.yml file to build a two-tier Flask application with a Flask backend and MySQL database.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751107963459/e1310dff-26c4-4200-a184-7591afc4a9d4.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751107976505/f33d042b-d700-4968-a099-e2028c47e9de.png" alt class="image--center mx-auto" /></p>
<p>At last, I understood Docker Registry—a centralized repository for storing, managing, and distributing Docker images. After logging into DockerHub using <code>docker login</code>, I learned to tag images and to push and pull from DockerHub. I pushed my two-tier-flask-app image to DockerHub, which I can use in the future to practice more.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751107983132/cd4ba37d-08bc-4698-a6e1-f12d0d1d318f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-resources-i-used">Resources I Used</h2>
<ol>
<li><p><a target="_blank" href="https://youtu.be/t8pPdKYpowI?si=rpjkg7_eFwzefIpd">Techworld With Nana | Python Tutorial</a></p>
</li>
<li><p><a target="_blank" href="https://boto3.amazonaws.com/v1/documentation/api/latest/index.html">Boto3 documentation</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/9bSbNNH4Nqw?si=j52eZKuwIfHuiIMk">TrainWithShubham | Docker</a></p>
</li>
</ol>
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p><strong>1️⃣ Python interpreter not working in Git Bash</strong></p>
<ul>
<li><p>The Python interpreter wasn't working properly in Git Bash when trying to run my automation scripts due to path recognition and environment variable issues.</p>
<p>  <strong>Solution:</strong> Switched to PowerShell which resolved the issue completely.</p>
</li>
</ul>
<p><strong>2️⃣ Wrong path error after deploying Docker container for canvas-assignment application</strong></p>
<ul>
<li><p>Encountered path errors that prevented the React application from loading correctly in the containerized environment.</p>
<p>  <strong>Solution:</strong> Replaced "homepage" line in package.json to "." and forced the PUBLIC_URL environment variable in Dockerfile.</p>
</li>
</ul>
<p><strong>3️⃣ Difficulty in creating health check in docker-compose.yml file</strong></p>
<ul>
<li><p>Had trouble understanding the syntax and getting the health check commands right for multi-container application monitoring.</p>
<p>  <strong>Solution:</strong> Referred to Docker Compose documentation and configured proper health checks that monitor both application status and database connectivity.</p>
</li>
</ul>
<h2 id="heading-whats-next">What's Next?</h2>
<p>For the next week, I am planning to write some more automation scripts using Python to understand more about scripting. I am also planning to combine all the Docker knowledge and use all the components to create a comprehensive project and then revise all these concepts.</p>
<h2 id="heading-lets-connect">Let's Connect!</h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/">My LinkedIn</a> 🔗 <a target="_blank" href="https://github.com/Akshansh029">My GitHub</a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I'd love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Understanding and Building with Jenkins: CI/CD Pipelines and AWS Integration]]></title><description><![CDATA[Introduction
Hello there! 👋 The past week was the 9th week of my DevOps learning journey, and I have to say that this was one of the toughest ones so far. Last week, I got started with CI/CD in Jenkins, and this week I continued to dive deeper into ...]]></description><link>https://blog.akshanshsingh.com/understanding-and-building-with-jenkins-cicd-pipelines-and-aws-integration</link><guid isPermaLink="true">https://blog.akshanshsingh.com/understanding-and-building-with-jenkins-cicd-pipelines-and-aws-integration</guid><category><![CDATA[Devops]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Jenkins]]></category><category><![CDATA[jenkins pipeline]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sat, 07 Jun 2025 07:46:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749282757470/f72a65f3-4ef8-485f-95be-0ccc05a01924.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! 👋 The past week was the 9th week of my DevOps learning journey, and I have to say that this was one of the toughest ones so far. Last week, I got started with CI/CD in Jenkins, and this week I continued to dive deeper into it. I learned and understood the Master-Slave Architecture in Jenkins, different types of build triggers and how they work, versioning of artifacts, Pipeline as Code, and learned to build an end-to-end CI/CD pipeline using different technologies.</p>
<h2 id="heading-master-slave-architecture">Master-Slave Architecture</h2>
<p>One of the most important concepts in Jenkins is understanding the <strong>Master-Slave Architecture</strong>. This architecture is used to distribute and organise the workload of running multiple jobs across different machines (physical, virtual, or cloud-based).</p>
<p><strong>Jenkins Master</strong> is the central server that hosts the Jenkins web UI, manages job configurations, schedules builds, and coordinates agents (slaves).</p>
<p><strong>Jenkins Slaves</strong> are remote machines that connect to the master and execute build jobs or specific stages (e.g., CPU-intensive tests, platform-specific builds) and then send the reports of the build back to the master.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*EhlDBJIG-nZ-KDeDUWr6lw.png" alt="Jenkins Master-Slave Architecture" class="image--center mx-auto" /></p>
<p>There are many benefits of this architecture:</p>
<ul>
<li><p><strong>Scalability</strong> - Distribute workloads across multiple machines; the master stays responsive.</p>
</li>
<li><p><strong>Isolation</strong> - Run builds in dedicated environments (different OS, JDK versions, or isolated containers).</p>
</li>
<li><p><strong>Platform diversity</strong> - Agents can run on Linux, Windows, macOS, or even containerised environments. It is useful when you need to test on multiple OSes or hardware architectures.</p>
</li>
<li><p><strong>Security</strong> - Master is protected (usually behind a firewall); only agents need SSH/JNLP access.</p>
</li>
<li><p><strong>Maintenance and upgrades</strong> - We can reboot or upgrade agents with minimal disruption, leaving the master unaffected.</p>
</li>
</ul>
<p>I also learned about the prerequisites required, such as OS considerations, requirements of Java, JRE and JDK, networking so master and slave agents can connect to each other, user permissions and working directories, etc. All this was theoretical knowledge needed to understand the benefits and working of Jenkins, so after this I learned to create slave agents using Jenkins and EC2 instances.</p>
<p>I created an Ubuntu EC2 instance with SSH access from my IP address and also from Jenkins Master. Then I installed Java, created the <code>jenkins-agent</code> user, and gave it the required permissions for the workspace. In the Jenkins Master, I added a new Node with remote root directory and the label. In Jenkins, we can assign jobs to different slaves or groups of slaves using labels, so it becomes important to carefully group the slaves which will be used for jobs for a specific project or task. To make use of labels, we have to select "Only build jobs with label expressions matching this node" in the Usage dropdown.</p>
<p>For credentials, I created a credential of "SSH Username with private key" kind with an ID which will be used to select it in the future. I copied the private key from the <strong>.pem</strong> file and pasted it in the private key section. After saving the configuration, I checked in the slave agent's workspace directory if there was a "remote" directory. If yes, the slave agent has been connected successfully to the master and is ready to be assigned jobs.</p>
<h2 id="heading-pipeline-as-code">Pipeline as Code</h2>
<p>A job in Jenkins can be of two types - Freestyle and Pipeline as Code. In freestyle jobs, we manually configure the job settings and build steps in the Freestyle job dashboard. Whereas in Pipeline as Code, it allows you to define the entire CI/CD process in a <strong>declarative or scripted syntax</strong> inside a <code>Jenkinsfile</code>. This file lives in the source code repository, enabling version control of the build process just like your application code.</p>
<p>Pipeline as Code is the standard for industry-level CI/CD pipelines as it helps in automation of the workflows, enables storing pipeline logic in source control, and provides advanced features like parallel execution, artifact management, and more.</p>
<p>A pipeline is of two types:</p>
<ol>
<li><p><strong>Declarative</strong> - Structured &amp; opinionated</p>
</li>
<li><p><strong>Scripted</strong> - Groovy-based &amp; flexible</p>
</li>
</ol>
<p>I understood the key components/blocks of a Jenkinsfile, such as pipeline, agent, environment, options, stages and stage, steps, when, and post block. Each type of block serves a different purpose and is useful in creating a pipeline. The Jenkinsfile is placed in the root directory of the source code repository so that Jenkins can automatically detect and run it when the pipeline job is configured properly. I created a few build pipelines with simple steps such as checking out code from GitHub, building the application using Maven, and running tests.</p>
<h2 id="heading-cicd-pipeline">CI/CD Pipeline</h2>
<p>After I learned and understood the basic working and management of Jenkins, it was time to put it all together and create something to gain hands-on knowledge. A CI/CD pipeline consists of checking out the code, running tests, building the artifact, running code analysis to check for bugs and vulnerabilities, storing the artifact in an artifact repository if it passes all the quality gates, and deploying it in the dev or staging environment.</p>
<p>At first, I decided to create a Continuous Integration pipeline only, which later became a complete CI/CD pipeline. The tools I decided to use for the CI pipeline:</p>
<ul>
<li><p><strong>Build tool</strong> - Maven</p>
</li>
<li><p><strong>Code Analysis</strong> - Sonar Scanner</p>
</li>
<li><p><strong>Storing the artifact</strong> - Nexus repository</p>
</li>
<li><p><strong>Notification</strong> - Slack Integration</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749281479032/2507fb58-5124-4153-a0a7-ee6357a96f2b.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-steps-for-creating-the-ci-pipeline">Steps for creating the CI pipeline:</h3>
<p><strong>1. Jenkins setup</strong></p>
<ul>
<li><p>Installing and configuring required JDK and Maven version</p>
</li>
<li><p>EC2 instance (Ubuntu, t2.medium)</p>
</li>
<li><p>Security group rules:</p>
<ul>
<li><p>SSH, port 22, my IP</p>
</li>
<li><p>Custom TCP, port 8080, my IP (Jenkins webpage access)</p>
</li>
<li><p>HTTP, port 80, Anywhere</p>
</li>
<li><p>Custom TCP, port 8080, Sonarqube-sg (Sonarqube communication)</p>
</li>
</ul>
</li>
</ul>
<p><strong>2. Nexus setup</strong></p>
<ul>
<li><p>EC2 instance (AWS Linux, t2.medium)</p>
</li>
<li><p>Configuring the setup through a script</p>
</li>
<li><p>Security group rules:</p>
<ul>
<li><p>SSH, port 22, my IP</p>
</li>
<li><p>Custom TCP, port 8081, my IP (Nexus webpage access)</p>
</li>
<li><p>Custom TCP, port 8081, Jenkins-sg (Publish artifact from Jenkins)</p>
</li>
</ul>
</li>
</ul>
<p><strong>3. SonarQube setup</strong></p>
<ul>
<li><p>EC2 instance (Ubuntu, t2.medium)</p>
</li>
<li><p>Configuring the setup through a script</p>
</li>
<li><p>Security group rules:</p>
<ul>
<li><p>SSH, port 22, my IP</p>
</li>
<li><p>HTTP, port 80, my IP (SonarQube webpage access)</p>
</li>
<li><p>HTTP, port 80, Jenkins-sg (Allow Jenkins to send reports)</p>
</li>
</ul>
</li>
</ul>
<p><strong>4. Installation of required plugins</strong></p>
<ul>
<li><p>Nexus artifact uploader</p>
</li>
<li><p>Sonar Scanner</p>
</li>
<li><p>Pipeline Maven integration</p>
</li>
<li><p>Build timestamp</p>
</li>
<li><p>Pipeline utility steps</p>
</li>
</ul>
<p><strong>5. Integration of</strong></p>
<ul>
<li><p>Nexus</p>
</li>
<li><p>SonarQube</p>
</li>
</ul>
<p><strong>6. Write Pipeline script</strong></p>
<p><strong>7. Set a notification using Slack</strong></p>
<p>After launching EC2 instances for Nexus and SonarQube, the real challenge was to integrate each of them with Jenkins. I won't be talking about these steps in-depth, but the high-level steps were to install the required plugins for these tools, configure the tools in Manage Jenkins &gt; Configure System, create authentication tokens for each of them so Jenkins can connect and communicate to them, provide it in Jenkins configuration, integrate custom quality gates for SonarQube, and configure the pipeline script with code analysis and upload artifact to Nexus steps.</p>
<p>After fixing a few typos and configuration errors, I was able to run the job successfully.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749281540682/cacd2591-8128-41e7-93b4-f8281775349a.png" alt class="image--center mx-auto" /></p>
<p>After creating this CI pipeline, the next step was to create a complete CI/CD pipeline using Docker, Docker Hub, and AWS ECR (Elastic Container Registry) and ECS (Elastic Container Service). For deploying the Docker image through ECS, I replaced the Nexus repository with AWS ECR.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749281572295/800fdd11-ebe1-43d9-9de8-8b74e28aefd0.png" alt /></p>
<h3 id="heading-steps-for-integrating-docker-aws-ecr-and-ecs">Steps for integrating Docker, AWS ECR and ECS-</h3>
<p><strong>1. Docker Engine in Jenkins</strong></p>
<ul>
<li><p>Installed Docker on the Jenkins server so it can <strong>build container images</strong></p>
</li>
<li><p>Required for using <code>docker</code> CLI commands in the pipeline</p>
</li>
</ul>
<p><strong>2. Add Jenkins User to Docker Group &amp; Reboot</strong></p>
<ul>
<li>Allows the Jenkins user to <strong>run Docker commands without sudo</strong></li>
</ul>
<p><strong>3. Install AWS CLI</strong></p>
<ul>
<li><p>Enables Jenkins to interact with AWS services like ECR from the command line</p>
</li>
<li><p>Used in the pipeline for commands like <code>aws ecr login</code></p>
</li>
</ul>
<p><strong>4. Create IAM User</strong></p>
<ul>
<li><p>A dedicated IAM user with programmatic access and permissions (<code>AmazonEC2ContainerRegistryFullAccess</code> and <code>AmazonECS_FullAccess</code>)</p>
</li>
<li><p>Ensures <strong>secure and scoped access</strong> to your AWS ECR for Jenkins</p>
</li>
</ul>
<p><strong>5. Create ECR Repository</strong></p>
<ul>
<li><p>Create an Elastic Container Registry to <strong>store and version Docker images</strong></p>
</li>
<li><p>The destination for built images to be pushed from Jenkins</p>
</li>
</ul>
<p><strong>6. Plugins: ECR, Docker Pipeline, AWS SDK</strong></p>
<ul>
<li><p><strong>ECR Plugin</strong> – Helps interact with ECR directly from Jenkins</p>
</li>
<li><p><strong>Docker Pipeline Plugin</strong> and CloudBees Docker – Enables Jenkins to run Docker build/push commands in a pipeline</p>
</li>
<li><p><strong>AWS SDK Plugin</strong> – Enables Jenkins to <strong>store and use AWS credentials securely</strong></p>
</li>
</ul>
<p><strong>7. Store IAM Credentials in Jenkins</strong></p>
<ul>
<li><p>Use <strong>Secret Text or AWS Credentials type</strong> under "Manage Credentials"</p>
</li>
<li><p>Required for Jenkins to <strong>authenticate with AWS</strong> in your pipeline securely</p>
</li>
</ul>
<p><strong>8. Create ECS Cluster and Task Definition</strong></p>
<ul>
<li><p>ECS Cluster is a logical grouping of tasks (Fargate or EC2) and services</p>
</li>
<li><p>Task Definition is like a blueprint for your container: image location, CPU/memory requirements, port mappings, and log settings</p>
</li>
</ul>
<p><strong>9. Create a Load Balancer and ECS service</strong></p>
<ul>
<li><p>Required to distribute traffic across multiple Fargate tasks and expose your service to the internet</p>
</li>
<li><p>Attach the ECS Service to Load Balancer which ensures that a specified number of tasks (containers) are always running</p>
</li>
</ul>
<p><strong>10. Run Pipeline</strong></p>
<ul>
<li><p>Executes stages like <strong>Docker build</strong>, <strong>login to ECR</strong>, and <strong>push</strong> image</p>
</li>
<li><p>Completes CI/CD by deploying containerised artifacts to the cloud registry</p>
</li>
</ul>
<p>The hardest part was learning and configuring AWS ECR and especially ECS. I did all these steps one at a time, and in between, I ran the job multiple times to test whether the steps were working fine. Again, each of these is much more elaborate than I mentioned, but I don't want to stretch the article that long. After writing the complete pipeline and checking beforehand for errors in the script, I created a new Pipeline Job, and seeing it build perfectly was such a rewarding feeling.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749281616895/acf44e80-da0c-429c-8728-935942d509e3.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749281669809/c512e7ed-c7da-4fbc-8eeb-82543ede15cb.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749281862563/3223adec-9183-41da-9f1a-60158ce095f6.png" alt /></p>
<p>For creating a CI/CD pipeline from scratch, it is very important to understand the flow of the pipeline and plan each step accordingly. Planning is as important as configuring and executing those steps.</p>
<p>At last, I learned while exploring Jenkins how <strong>Authentication and Authorization</strong> work. Jenkins allows the admin to control exactly who can do what - like accessing the dashboard, reading or editing jobs, configuring pipelines, or deleting them. I learned how large companies manage multiple users working on different projects at the same time using Jenkins. They create <strong>roles</strong> that group users based on their responsibilities, and then assign the same set of permissions to everyone in that role. This not only makes user management easier but also saves a lot of time and reduces the chances of mistakes.</p>
<h2 id="heading-resources-i-used">Resources I used-</h2>
<ol>
<li><p><a target="_blank" href="https://docs.docker.com/engine/install/ubuntu/">Docker Installation</a></p>
</li>
<li><p><a target="_blank" href="https://slack.com/intl/en-in/marketplace">Slack Marketplace</a></p>
</li>
<li><p><a target="_blank" href="https://www.udemy.com/course/decodingdevops/">DevOps Course | Udemy</a></p>
</li>
</ol>
<h2 id="heading-challenges-i-faced">Challenges I faced-</h2>
<p><strong>1️⃣ Disk space issue in the Jenkins server</strong></p>
<ul>
<li>8 GB volume was not enough to run multiple build jobs in the Jenkins server and the jobs kept crashing.</li>
</ul>
<p><strong>Solution:</strong> Increased the EBS volume from 8 GB to 20 GB for the Jenkins EC2 instance.</p>
<p><strong>2️⃣ URL issues for different servers</strong></p>
<ul>
<li>For accessing the web pages of Jenkins, Nexus, and SonarQube, when I pasted the public IPs for each instance in the browser, I wasn't able to access the web pages.</li>
</ul>
<p><strong>Solution:</strong> For some reason, the URL was using HTTPS for these public IPs, so I had to manually type <code>http://&lt;INSTANCE_PUBLIC_IP&gt;</code> and then I was able to access the web pages.</p>
<p><strong>3️⃣ Unable to connect the Slave agent with Master</strong></p>
<ul>
<li>When adding a new Node in Jenkins Master, I was using the public IP of the slave EC2 instance in the "Host" input and it wasn't connecting to master for that configuration.</li>
</ul>
<p><strong>Solution:</strong> I replaced the public IP address with the private IP address of the slave's EC2 instance, which worked for me.</p>
<h2 id="heading-whats-next"><strong>What's Next?</strong></h2>
<p>To be honest, it was one of the toughest things to learn so far as there were too many things to learn in Jenkins, and along with that, I learned about integration with SonarQube, Nexus, AWS ECR, and AWS ECS. So firstly, I would revise all the concepts of Jenkins once again, go through all the steps of creating a pipeline to fully understand the flow, and then next week get started with <strong>Python</strong>. It was a long article as I had to cover a lot of stuff - sorry about that, and thank you if you still read it till here! :)</p>
<h2 id="heading-lets-connect"><strong>Let's Connect!</strong></h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>My LinkedIn</strong></a></p>
<p>🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I'd love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[From GitHub SaaS Project to CI/CD Automation]]></title><description><![CDATA[Introduction
Hello there! 👋 It's been a while since I last posted because of exams and a week of relaxation after coming back to my hometown for vacation. But in the meantime, I managed to do some useful work, and this past week, I got back on track...]]></description><link>https://blog.akshanshsingh.com/from-github-saas-project-to-cicd-automation</link><guid isPermaLink="true">https://blog.akshanshsingh.com/from-github-saas-project-to-cicd-automation</guid><category><![CDATA[Devops]]></category><category><![CDATA[Learning Journey]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[Jenkins]]></category><category><![CDATA[github-actions]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sun, 01 Jun 2025 18:10:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748801134936/292b13e2-8ff0-4e35-a4f3-a9803c8cca4e.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! 👋 It's been a while since I last posted because of exams and a week of relaxation after coming back to my hometown for vacation. But in the meantime, I managed to do some useful work, and this past week, I got back on track with my DevOps learning. So for the past few weeks, I had been working on an AI GitHub SaaS project, and this week I got started with CI/CD processes using GitHub Actions and Jenkins.</p>
<h2 id="heading-github-saas-project">GitHub SaaS Project</h2>
<p>Previously, after finishing any of my projects, I wanted to document them for GitHub. I used to either create the README for that project on GitHub manually or give the context of what my project does to ChatGPT and just hope it would do a good job understanding the idea and context of the project. So then I thought, what if I create my own app to generate READMEs for my projects by using all of the context of my project directly from GitHub? From then on, I started researching about the GitHub API, how to get the source code of any project, and give it to any LLM to generate a perfect README for me.</p>
<p>Through the Octokit library, we can interact with the GitHub API and get the source code, but what if the source code for each file goes beyond the context limit of Gemini? So to solve this problem, I came to know about a method called "Prompt Chaining." In this method, first, we ignore the irrelevant files like package.json, node_modules, yarn.lock, bun.lock, .env, etc. Then we generate a summary for each relevant file. We store the summaries of all the relevant files in our database and then pass all those summaries as context to create the README.</p>
<p>While researching about this method, I was discussing with one of my friends about this, and he gave me a suggestion that if I can get the context of any project efficiently, I can do whatever I want with that data. And that sparked another idea - we can implement a Q&amp;A-based feature where users can query anything about their codebase. But there's a problem with that too: how can we answer specific queries about anything from the codebase? How can we know which files are relevant for the query? The answer to that was Text Embedding.</p>
<p>We can create vector embeddings of the queries and the files of the codebase, and through matching them, we will get the relevant files and the required answer to the query using AI. I learned a few necessary things about Text Embedding and Vector databases and how I can use them in my project. For that, along with the generation of the summary of each file, we would also need to generate the embedding of the summary of each file and store it. Through them, we will get the answer to the query asked about the codebase. This could be very useful for junior developers or interns joining a new project or for open source projects where contributors want to have a thorough understanding of the codebase before contributing.</p>
<p>The tech stack I used for this project:</p>
<p>🔹 NextJS</p>
<p>🔹 TypeScript</p>
<p>🔹 TRPC</p>
<p>🔹 TailwindCSS</p>
<p>🔹 Shadcn</p>
<p>🔹 Clerk</p>
<p>🔹 Google Gemini API</p>
<p>🔹 Razorpay</p>
<p>🔹 PostgreSQL</p>
<p>🔹 Prisma</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748800581877/85e1ea03-8eb3-4aaa-9fab-ea579a505f07.png" alt class="image--center mx-auto" /></p>
<p>Feel free to check out the project and GitHub repository. Also, if you have any suggestions to improve the website, please do let me know.</p>
<p><strong>GitHub link of the project:</strong> <a target="_blank" href="https://github.com/Akshansh029/Nebulo">https://github.com/Akshansh029/Nebulo</a></p>
<p><strong>Project link:</strong> <a target="_blank" href="https://nebulo-zeta.vercel.app">https://nebulo-zeta.vercel.app</a></p>
<h2 id="heading-getting-started-with-cicd">Getting Started with CI/CD</h2>
<h3 id="heading-cicd-with-github-actions">CI/CD with GitHub Actions</h3>
<p>After completing the project and deploying it, this week I got back on track with DevOps. It was time to start one of the most important topics of DevOps - Continuous Integration and Continuous Delivery (CI/CD). As I had already studied about CI/CD and the principles used in it, I did a quick recap and wanted to start with the implementation part. I started with GitHub Actions.</p>
<p><strong>GitHub Actions</strong> is a built-in <strong>CI/CD automation tool</strong> in GitHub. It lets you run workflows directly in your repository to automate tasks like:</p>
<ul>
<li><p>Building code</p>
</li>
<li><p>Running tests</p>
</li>
<li><p>Deploying to production</p>
</li>
</ul>
<p>It works using <strong>YAML configuration files</strong> inside your repository.</p>
<p>The workflows are defined inside:</p>
<pre><code class="lang-bash">.github/
└── workflows/
    ├── ci.yml
    └── deploy.yml
</code></pre>
<p>Key components of a workflow are:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Component</td><td>Purpose</td></tr>
</thead>
<tbody>
<tr>
<td><code>on</code></td><td>Event triggers (e.g. <code>push</code>, <code>pull_request</code>, <code>schedule</code>)</td></tr>
<tr>
<td><code>jobs</code></td><td>Defines units of work (can be parallel)</td></tr>
<tr>
<td><code>runs-on</code></td><td>Specifies the runner OS (<code>ubuntu-latest</code>, <code>windows-latest</code>, etc.)</td></tr>
<tr>
<td><code>steps</code></td><td>Sequence of actions or commands</td></tr>
<tr>
<td><code>uses:</code></td><td>Reusable GitHub Actions (like DockerHub for CI/CD)</td></tr>
<tr>
<td><code>run:</code></td><td>Shell command you write directly</td></tr>
</tbody>
</table>
</div><p>The steps defined in the .yml file are executed in virtual or physical machines called <code>Runners</code>. There are two types of runners which GitHub provides:</p>
<ol>
<li><p><strong>GitHub Hosted Runners (Shared)</strong> - These are provided by GitHub with pre-configured environments.</p>
</li>
<li><p><strong>Self-hosted Runners</strong> - Users install and manage them and have complete control over hardware and OS.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748800594908/929fae8c-5374-4062-9835-a415ae2fcc4e.png" alt class="image--center mx-auto" /></p>
<p>I learned different concepts and components of GitHub Actions and how to use them in a workflow, such as using multiple jobs, environment variables, job concurrency, matrix strategy, etc. As practice, I wrote and used two workflows - one to build and test the source code of a Node application and another to build the Docker Image and store it in DockerHub.</p>
<p><strong>integration.yml:</strong></p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">Build</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">"main"</span>]
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">"main"</span>]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">strategy:</span>
      <span class="hljs-attr">matrix:</span>
        <span class="hljs-attr">node-version:</span> [<span class="hljs-number">18.</span><span class="hljs-string">x</span>, <span class="hljs-number">20.</span><span class="hljs-string">x</span>, <span class="hljs-number">22.</span><span class="hljs-string">x</span>]

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v4</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">node-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">cache:</span> <span class="hljs-string">"npm"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">command</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>

  <span class="hljs-attr">unit-tests:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">needs:</span> <span class="hljs-string">build</span>
    <span class="hljs-attr">strategy:</span>
      <span class="hljs-attr">matrix:</span>
        <span class="hljs-attr">node-version:</span> [<span class="hljs-number">18.</span><span class="hljs-string">x</span>, <span class="hljs-number">20.</span><span class="hljs-string">x</span>, <span class="hljs-number">22.</span><span class="hljs-string">x</span>]

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v4</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">node-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">cache:</span> <span class="hljs-string">"npm"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Running</span> <span class="hljs-string">unit</span> <span class="hljs-string">test</span> <span class="hljs-string">cases</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">test</span>
</code></pre>
<p><strong>deploy.yml:</strong></p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">on</span> <span class="hljs-string">DockerHub</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">"main"</span>]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Build</span> <span class="hljs-string">process</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">docker</span> <span class="hljs-string">build</span> <span class="hljs-string">.</span> <span class="hljs-string">-t</span> <span class="hljs-string">akshansh29/next-js-app:latest</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">DockerHub</span> <span class="hljs-string">login</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">echo</span> <span class="hljs-string">"$<span class="hljs-template-variable">{{secrets.DOCKERHUB_PASSWORD}}</span>"</span> <span class="hljs-string">|</span> <span class="hljs-string">docker</span> <span class="hljs-string">login</span> <span class="hljs-string">-u</span> <span class="hljs-string">${{secrets.DOCKERHUB_USERNAME}}</span> <span class="hljs-string">--password-stdin</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Pushing</span> <span class="hljs-string">image</span> <span class="hljs-string">to</span> <span class="hljs-string">DockerHub</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">docker</span> <span class="hljs-string">push</span> <span class="hljs-string">akshansh29/next-js-app:latest</span>
</code></pre>
<h3 id="heading-cicd-with-jenkins">CI/CD with Jenkins</h3>
<p><strong>Jenkins</strong> is one of the most used DevOps tools to automate CI/CD workflows. It is an open-source <strong>automation server</strong> used to automate software development processes. Some core features of Jenkins are:</p>
<ul>
<li><p><strong>Pipeline as Code</strong> using <code>Jenkinsfile</code></p>
</li>
<li><p><strong>Extensible plugin ecosystem</strong> (e.g., Git, Maven, Docker, Slack, Kubernetes)</p>
</li>
<li><p><strong>Distributed builds</strong> using master-agent architecture</p>
</li>
<li><p>Supports <strong>polling SCM</strong> or <strong>webhooks</strong> for triggering builds</p>
</li>
<li><p>Can <strong>schedule jobs</strong> (cron-like syntax)</p>
</li>
<li><p>Provides a <strong>dashboard</strong> and build history</p>
</li>
</ul>
<p>To get started with Jenkins, I referred to the Jenkins docs for the installation guide. I created an EC2 instance to run the Jenkins server on it, SSH into it, and I copied the Linux commands to install Jenkins from the docs and set up the Jenkins server. I learned about the home directory of Jenkins, i.e., <code>/var/lib/jenkins</code>, where all the files of Jenkins are stored. Using the instance's IP address and port number, I accessed the Jenkins web page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748800629291/9e6beb32-9782-4e0e-afff-b7b68f198a15.png" alt class="image--center mx-auto" /></p>
<p>I also learned about Jobs - A <strong>Job</strong> in Jenkins is a task or project that Jenkins performs, such as pulling code from a repository, building a project, running tests, etc. It is of two types:</p>
<ol>
<li><p><strong>Freestyle project</strong> - A simple, GUI-based job configuration which is ideal for small or basic automation tasks.</p>
</li>
<li><p><strong>Pipeline as Code</strong> - Jenkins Pipeline is a suite of plugins that support <strong>pipeline as code</strong> using a <strong>Jenkinsfile</strong>, which is a plain-text file checked into the source repository, enabling complex automation scenarios with full control.</p>
</li>
</ol>
<p>Till now, I have learned how to create Freestyle projects and how to install plugins and tools in Jenkins. I learned how I can configure a freestyle project to install different tools like Git and Maven using shell commands and also by using the "Build Environment" section and selecting required tools. I configured a build job in which it should fetch the code from a GitHub repository, run the required tests, and build the artifact. All the relevant files and artifacts are stored in the workspace in the build section.</p>
<h2 id="heading-resources-i-used">Resources I Used</h2>
<ol>
<li><p><a target="_blank" href="https://youtu.be/E2RRxcq_08E?si=k32kCsPKzHcSjEIi">GitHub Actions | KodeKloud</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/AknbizcLq4w?si=luCvOd9FdPm_TlUZ">CI/CD Explained | TechWorld with Nana</a></p>
</li>
<li><p><a target="_blank" href="https://www.jenkins.io/doc/book/installing/">Installation guide | Jenkins</a></p>
</li>
<li><p>DevOps Course | Udemy</p>
</li>
</ol>
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p><strong>1️⃣ Too many requests to GitHub API</strong></p>
<p><strong>Solution:</strong> Collected only relevant files by filtering out using file extensions and implemented <strong>Exponential Backoff with retries</strong>, which is a strategy where you wait progressively longer before retrying a failed request. The delay increases exponentially (e.g., 500ms, 1000ms, 2000ms).</p>
<p><strong>2️⃣ Error in testing the Vprofile using Maven due to a different JDK version</strong></p>
<p><strong>Solution:</strong> Installed the required JDK version.</p>
<p><strong>3️⃣ Jenkins webpage access issue</strong></p>
<p><strong>Solution:</strong> Changed the inbound rule from my IP to every IPv4 address for testing and rebooted the instance.</p>
<h2 id="heading-whats-next">What's Next?</h2>
<p>I'll continue learning Jenkins, which is an essential tool that I want to master. I will learn about Pipeline as Code, practice by creating different pipelines, and make a project to create an end-to-end CI/CD pipeline.</p>
<h2 id="heading-lets-connect">Let's Connect!</h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>My LinkedIn</strong></a></p>
<p>🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I'd love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Building on the Cloud: AWS Services and a Hands-On Java App Deployment]]></title><description><![CDATA[Introduction
Hello there! 👋 The past week marked Week 7 of my DevOps journey, and this time, I started by revisiting concepts of Computer Networks, as it’s been a while since I looked back at them. I continued my AWS learning by exploring services l...]]></description><link>https://blog.akshanshsingh.com/building-on-the-cloud-aws-services-and-a-hands-on-java-app-deployment</link><guid isPermaLink="true">https://blog.akshanshsingh.com/building-on-the-cloud-aws-services-and-a-hands-on-java-app-deployment</guid><category><![CDATA[Devops]]></category><category><![CDATA[learning]]></category><category><![CDATA[Learning Journey]]></category><category><![CDATA[AWS]]></category><category><![CDATA[deployment]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sat, 19 Apr 2025 06:13:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745043165884/103d3a4f-bce0-43e8-9e13-39f3b9702f4d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! 👋 The past week marked <strong>Week 7</strong> of my DevOps journey, and this time, I started by revisiting concepts of Computer Networks, as it’s been a while since I looked back at them. I continued my AWS learning by exploring services like <strong>EFS</strong>, <strong>Auto Scaling Groups</strong>, <strong>S3</strong>, and <strong>RDS</strong>. To revise and implement my previous learnings, I built a project called <code>Vprofile</code>, where I used AWS services to deploy a Java-based application using EC2, S3, Load Balancers, Route 53, and Auto Scaling Groups.</p>
<h2 id="heading-exploring-aws-storage-services"><strong>Exploring AWS Storage Services</strong></h2>
<h3 id="heading-elastic-file-system-efs"><strong>Elastic File System (EFS)</strong></h3>
<p>AWS has many options for storage, and as a DevOps learner, I should be proficient in using these storage services. The first one is <code>EFS or Elastic File System</code>. It is a fully managed, scalable NFS file system that can simultaneously be mounted on multiple EC2 instances. EFS is like a virtual hard disk which can store and protect our data from EC2 instances, Lambda, ECS, EKS, etc. Some of its key features are</p>
<ul>
<li><p><strong>Shared file storage</strong> for Linux workloads</p>
</li>
<li><p><strong>Elastic &amp; Scalable</strong>: Automatically grows/shrinks as files are added/removed</p>
</li>
<li><p>Supports <strong>POSIX-compliant</strong> permissions (Linux-style)</p>
</li>
<li><p>Accessible across <strong>multiple AZS</strong></p>
</li>
<li><p><strong>Use Cases</strong>: Web servers, CMS, containers (EKS, ECS), CI/CD, ML, shared file access</p>
</li>
</ul>
<p>After covering some theoretical knowledge of EFS, I jumped into how to create and mount one in an EC2 instance. I followed the following high-level steps to accomplish this-</p>
<ol>
<li><p>Create an EFS File System in the AWS Management Console</p>
</li>
<li><p>Create Access Point for EFS (Recommended)</p>
</li>
<li><p>Configure the Security Group to allow an NFS type inbound rule for port 2049</p>
</li>
<li><p>Configure EC2 Instance</p>
<h3 id="heading-for-amazon-linux-2-amazon-linux-ami">For <strong>Amazon Linux 2 / Amazon Linux AMI</strong></h3>
<pre><code class="lang-bash"> sudo yum update -y
 sudo yum install -y amazon-efs-utils
</code></pre>
<h3 id="heading-for-debianubuntu">For <strong>Debian/Ubuntu</strong></h3>
<pre><code class="lang-bash"> sudo apt update
 sudo apt install -y amazon-efs-utils
</code></pre>
</li>
<li><p>Create a Mount Directory inside the EC2 instance (eg, /mnt/efs)</p>
</li>
<li><p>Mount EFS Temporarily (Test)</p>
<pre><code class="lang-bash"> sudo mount -t efs -o tls,accesspoint=access_point_id efs_file_system_id:/ /mnt/efs
</code></pre>
</li>
<li><p>Verify using:</p>
<pre><code class="lang-bash"> df -h
</code></pre>
</li>
<li><p>Mount Persistently Using <code>/etc/fstab</code></p>
</li>
<li><p>Test and check using:</p>
<pre><code class="lang-bash"> sudo mount -a
 df -h
</code></pre>
</li>
</ol>
<h3 id="heading-simple-storage-service-s3"><strong>Simple Storage Service (S3)</strong></h3>
<p>After EFS, I moved to <code>Simple Storage Service (S3)</code> . It is a service that stores files of different types, like Photos, Audio, and Videos, as Objects, providing more scalability and security. The main components of S3 are Bucket, Key, and Object. S3 has many use cases, like-</p>
<ul>
<li><p>Static website hosting</p>
</li>
<li><p>Backup and restore</p>
</li>
<li><p>Data archiving</p>
</li>
<li><p>Big data analytics</p>
</li>
<li><p>Disaster recovery</p>
</li>
</ul>
<p>and many more. The thing I liked about S3 is that it is really simple to get started with S3. There’s not much hassle in using S3. I learned about different classes of S3.</p>
<p>I also learned about versioning, access control using bucket policies, IAM policies, ACLs and Lifecycle policies, which is how we can configure the transition of objects between storage classes based on how old they are. I also learned to host a static website using S3 buckets and how disaster management is done using replication rules.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745042504158/19c9a5b5-a607-4af0-9f05-5b29e8004572.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-relational-database-service-rds"><strong>Relational Database Service (RDS)</strong></h3>
<p>The next storage service was <code>RDS or Relational Database Service</code> and unlike S3, it wasn’t easy for me to grasp. It is a managed <strong>Relational Database Service</strong> supporting engines such as Mysql, Postgresql, Mariadb, Oracle, SQL Server, and Amazon Aurora. Some of its key features I came to know-</p>
<ul>
<li><p><strong>Automated Backups</strong>: Point‑in‑time recovery with daily snapshots and transaction logs</p>
</li>
<li><p><strong>Multi‑AZ Deployments</strong>: Synchronous standby in a separate Availability Zone for failover</p>
</li>
<li><p><strong>Read Replicas</strong>: Scale read workloads and offload reporting</p>
</li>
<li><p><strong>Storage Auto Scaling</strong>: Automatically increase storage when you approach capacity limits</p>
</li>
<li><p><strong>Encryption at Rest &amp; In Transit</strong>: AWS KMS–managed keys or customer‑managed keys</p>
</li>
<li><p><strong>Monitoring &amp; Metrics</strong>: Integration with CloudWatch, enhanced monitoring, Performance Insights</p>
</li>
<li><p><strong>Maintenance Windows</strong>: Automatic minor version upgrades during a defined time window</p>
</li>
</ul>
<p>It has many use cases in real-world applications like web and mobile applications that require relational schema, analytics and reporting with read-heavy queries, etc. I learned how to create an RDS instance, how to configure it, how to delete it and learned about a few best practices for RDS.</p>
<h2 id="heading-project-highlight-vprofile-deployment-on-aws"><strong>Project Highlight: Vprofile Deployment on AWS</strong></h2>
<p>And to practice and implement a few services which I learned, I made a project to deploy a multi-tier Java application. Building a project is always the fun part of learning (till you encounter an unsolvable error and lose all your motivation 🙂). The services I used for this project are-</p>
<ol>
<li><p><code>EC2 Instances</code> - VM for Tomcat, RabbitMQ, MemCache, MySQL</p>
</li>
<li><p><code>Elastic Load Balancer (ELB)</code> - Nginx Load Balancer replacement</p>
</li>
<li><p><code>Auto Scaling Groups</code> - Automation for VM scaling</p>
</li>
<li><p><code>S3/EFS Storage</code> - Shared storage</p>
</li>
<li><p><code>Route 53</code> - Private DNS service</p>
</li>
<li><p><code>IAM</code> - To create a user and a role for S3 full access</p>
</li>
</ol>
<h3 id="heading-the-architecture-of-the-project">The architecture of the project-</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745042540324/9c4df348-217d-46ae-8ec8-f8dcfd1d2123.png" alt class="image--center mx-auto" /></p>
<p>The user accesses the application via a custom domain registered on GoDaddy, which routes traffic through an HTTPS-enabled Elastic Load Balancer (ELB). The ELB forwards requests on port 8080 to an Auto Scaling Group of EC2 instances, ensuring high availability and performance. These instances interact with backend services, including Rabbitmq for messaging, Mysql for database operations, and Memcached for caching, all hosted on separate EC2 instances within a secure group. The setup also integrates Route 53 for DNS management (with Private Zones) and uses S3 buckets to store application artifacts, making the deployment both scalable and modular.</p>
<p>While there's a lot more depth to how each service was integrated and managed, for now, I’ll focus on outlining the key steps of the overall process to give a clear high-level view.</p>
<h3 id="heading-steps-involved">Steps involved-</h3>
<ol>
<li><p><strong>Set Up Security Groups</strong></p>
<p> Created separate security groups for the Load Balancer, Tomcat app server, and backend services (Mysql, Memcache, Rabbitmq). Each group had tightly scoped rules- like allowing port 8080 access from the ELB SG or enabling internal backend communication via private IPs and ports.</p>
</li>
<li><p><strong>Create a Key Pair for SSH Access</strong></p>
<p> Generated an AWS key pair to securely SSH into EC2 instances during setup and troubleshooting.</p>
</li>
<li><p><strong>Launch EC2 Instances for Backend Services</strong></p>
<p> Used Amazon Linux AMI to launch instances for Mysql, Memcached, and Rabbitmq. Applied startup scripts from the <code>vprofile</code> repo during instance creation and attached the appropriate backend security group.</p>
</li>
<li><p><strong>Configure Private DNS with Route 53</strong></p>
<p> Created a <strong>Private Hosted Zone</strong> in Route 53 to map backend service hostnames (e.g., <code>db01.vprofile.in</code>) to their private IPs. This made service-to-service communication IP-independent.</p>
</li>
<li><p><strong>Test DNS Resolution</strong></p>
<p> Verified hostname resolution by SSHing into the Tomcat instance and pinging other backend services using their DNS names (e.g., <code>ping -c 4 db01.vprofile.in</code>).</p>
</li>
<li><p><strong>Build the Java Artifact Using Maven</strong></p>
<p> Cloned the <code>vprofile</code> source code locally, built the <code>.war</code> file using <code>mvn install</code>, and verified the build in the <code>target</code> directory.</p>
</li>
<li><p><strong>Set Up S3 for Artifact Storage</strong></p>
<p> Created an S3 bucket to store the built <code>.war</code> file. Used AWS CLI to upload the artifact. An IAM user with S3 access was configured locally for this step.</p>
</li>
<li><p><strong>Assign IAM Role to Tomcat EC2 Instance</strong></p>
<p> Created an IAM role with full S3 access and attached it to the Tomcat instance so it could pull the <code>.war</code> file directly during deployment without AWS credentials.</p>
</li>
<li><p><strong>Deploy the Application on Tomcat</strong></p>
<p> Pulled the <code>.war</code> from S3 into the Tomcat EC2 instance, replaced the default webapps directory with the new artifact, and restarted the Tomcat service to reflect the changes.</p>
</li>
<li><p><strong>Set Up Application Load Balancer (ALB)</strong></p>
<p>Created a target group pointing to the Tomcat instance on port 8080 and attached it to a newly created ALB. Enabled both HTTP/HTTPS (if SSL cert is present). The ALB DNS name served as the public entry point.</p>
</li>
<li><p><strong>Test Application via Load Balancer</strong></p>
<p>Verified successful deployment by accessing the app through the ELB DNS URL. Ensured all backend services were communicating correctly through configured hostnames.</p>
</li>
<li><p><strong>Configure Auto Scaling with Launch Template</strong></p>
<p>Created an AMI from the configured Tomcat instance, set up a launch template with required settings and IAM role, and finally created an Auto Scaling Group to automatically manage Tomcat app server instances.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745042607582/fdb52046-f5ad-4930-aec8-2f7b3c129a88.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745042613789/2e3ddf6b-30f4-496f-82c9-67e908bc813e.png" alt class="image--center mx-auto" /></p>
<p>For now, I skipped purchasing a domain name and configuring the ELB DNS name with it. Doing so would have given this project a more realistic approach, but that can be done in future projects.</p>
<h2 id="heading-resources-i-used">Resources I used-</h2>
<ol>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/whitepapers/latest/aws-overview/storage-services.html">Storage Services | AWS Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://www.geeksforgeeks.org/amazon-rds-creating-an-amazon-rds-db-instance/">RDS Instance | geekforgeeks</a></p>
</li>
<li><p><a target="_blank" href="https://www.udemy.com/course/decodingdevops">DevOps Course | Udemy</a></p>
</li>
</ol>
<h3 id="heading-challenges-i-faced">Challenges I faced-</h3>
<p>1️⃣ <code>Difficulty in understanding RDS instances</code> - I couldn’t grasp the concept of RDS instantly. I learned how to create an RDS instance and how to modify/delete it, but I have to figure out how to implement it.</p>
<p>Solution - I will try to create a mini project to implement and understand the flow of how RDS is used.</p>
<p>2️⃣ <code>SSL-related error mid-upload when using the AWS CLI</code> - When I was trying to copy the artifact from the local system to the S3 bucket using AWS CLI, I was getting an SSL-related error, and my connection with the S3 bucket kept getting interrupted. I thought it was a Git Bash issue as I was using Bash. I tried using PowerShell but kept getting the same error. Solution- As the connection was getting interrupted during the artifact upload, I came to know that it could be a network-related issue. So I changed the wifi from my hostel wifi to my personal hotspot, and now there was no error, and the artifact was uploaded successfully.</p>
<h2 id="heading-whats-next"><strong>What’s Next?</strong></h2>
<p>From next week, my end-of-semester exams are going to be held, so it would be difficult to continue learning new services and publish articles. So, I will go through all the AWS services I have learnt till now and revise them</p>
<h2 id="heading-lets-connect"><strong>Let’s Connect!</strong></h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>My LinkedIn</strong></a> 🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I’d love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[From Docker Demos to EC2 Deployments]]></title><description><![CDATA[Introduction
Hello there! 👋 The past week marked Week 6 of my DevOps journey, and it was the beginning of something more hands-on and real-world focused. After completing most of the fundamental concepts, I was about to start learning Docker and Kub...]]></description><link>https://blog.akshanshsingh.com/from-docker-demos-to-ec2-deployments</link><guid isPermaLink="true">https://blog.akshanshsingh.com/from-docker-demos-to-ec2-deployments</guid><category><![CDATA[Devops]]></category><category><![CDATA[learning]]></category><category><![CDATA[Learning Journey]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sun, 13 Apr 2025 06:47:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744525828203/afcfd8ca-2c60-4e5c-842b-1aa4953dc210.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! 👋 The past week marked <strong>Week 6</strong> of my DevOps journey, and it was the beginning of something more hands-on and real-world focused. After completing most of the fundamental concepts, I was about to start learning Docker and Kubernetes, but a YouTube video changed the course a bit.</p>
<p>It is recommended learning cloud computing first, then explore containerization and deployment tools <em>in the context of the cloud.</em> That clicked for me. So, this week, I started exploring containerization concepts, got familiar with microservices architecture, and kicked off with AWS Fundamentals. Here's how the week unfolded:</p>
<hr />
<h2 id="heading-understanding-containerization-and-docker">Understanding Containerization and Docker</h2>
<p>I began with a simple question: <strong>"What is a container?"</strong></p>
<p><strong>Containers</strong> are lightweight, portable environments that package an application and all its dependencies together.</p>
<h3 id="heading-advantages-of-containers">Advantages of Containers:</h3>
<ul>
<li><p>Consistency across development, testing, and production.</p>
</li>
<li><p>Portability across platforms (Docker, Podman).</p>
</li>
<li><p>Scalability for service expansion and contraction.</p>
</li>
<li><p>Efficiency compared to VMs.</p>
</li>
</ul>
<p>The most widely used tool for containerization, as we all know, is <strong>Docker</strong>. So, I learned about Docker, a platform for developing, shipping, and running applications in containers.<br />I understood the flow for creating a Docker container -</p>
<ul>
<li><p>Write a Dockerfile with commands like <code>FROM</code>, <code>RUN</code>, <code>CMD</code>, etc.</p>
</li>
<li><p>Build a Docker Image from the Dockerfile.</p>
</li>
<li><p>Use that image to run a Docker Container.</p>
</li>
</ul>
<h3 id="heading-docker-architecture">Docker Architecture</h3>
<p>Docker follows a Client-Server model:</p>
<ul>
<li><p>Docker Client → CLI or GUI for user interaction</p>
</li>
<li><p>Docker Daemon → Manages containers in the background</p>
</li>
<li><p>Docker Registry → Stores Docker images (e.g., DockerHub)</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744525509926/877e8433-0af0-4f63-8b2d-e2a2e2b10631.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-scenario-nginx-web-server-in-docker">Scenario: Nginx Web Server in Docker</h3>
<p>I noted a simple scenario for reference: running an Nginx Web Server in Docker. It involves the following steps -</p>
<ol>
<li><p>Install <strong>Docker</strong> on your system.</p>
</li>
<li><p>Pull the Nginx image** from DockerHub</p>
<pre><code class="lang-bash"> docker pull nginx
 docker run -d -p 8080:80 --name my-nginx nginx
</code></pre>
<p> Visit <code>http://localhost:8080</code> to see it in action.</p>
</li>
<li><p>Container Management</p>
<pre><code class="lang-bash"> docker ps
 docker stop my-nginx
 docker rm my-nginx
</code></pre>
</li>
</ol>
<p>To get a hold of how Docker containers are created and run inside a VM, I set up Docker inside a VM:</p>
<ol>
<li><p>Create a VM using Vagrant and configure it using Vagrantfile.</p>
</li>
<li><p>Run the VM using vagrant up, log in to it using SSH and switch to the root user.</p>
</li>
<li><p>Basic Commands</p>
<pre><code class="lang-bash"> systemctl status docker
 docker run hello-world

 docker images
 docker ps
 docker ps -a
</code></pre>
</li>
<li><p>Run a container</p>
</li>
<li><p>Building an image</p>
<pre><code class="lang-bash"> mkdir images
 <span class="hljs-built_in">cd</span> images/
 vim Dockerfile
</code></pre>
<pre><code class="lang-docker"> <span class="hljs-keyword">FROM</span> ubuntu:latest AS BUILD_IMAGE
 <span class="hljs-keyword">RUN</span><span class="bash"> apt update &amp;&amp; apt install wget unzip -y</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> wget https://www.tooplate.com/zip-templates/2128_tween_agency.zip</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> unzip 2128_tween_agency.zip &amp;&amp; <span class="hljs-built_in">cd</span> 2128_tween_agency &amp;&amp; tar -czf tween.tgz * &amp;&amp; mv tween.tgz /root/tween.tgz</span>

 <span class="hljs-keyword">FROM</span> ubuntu:latest
 <span class="hljs-keyword">LABEL</span><span class="bash"> <span class="hljs-string">"project"</span>=<span class="hljs-string">"Marketing"</span></span>
 <span class="hljs-keyword">ENV</span> DEBIAN_FRONTEND=noninteractive

 <span class="hljs-keyword">RUN</span><span class="bash"> apt update &amp;&amp; apt install apache2 git wget -y</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> --from=BUILD_IMAGE /root/tween.tgz /var/www/html/</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">cd</span> /var/www/html/ &amp;&amp; tar xzf tween.tgz</span>
 <span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"/usr/sbin/apache2ctl"</span>, <span class="hljs-string">"-D"</span>, <span class="hljs-string">"FOREGROUND"</span>]</span>
 <span class="hljs-keyword">VOLUME</span><span class="bash"> /var/<span class="hljs-built_in">log</span>/apache2</span>
 <span class="hljs-keyword">WORKDIR</span><span class="bash"> /var/www/html/</span>
 <span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span>
</code></pre>
<pre><code class="lang-bash"> docker build -t tesimg .
 docker images
 <span class="hljs-comment"># Run container from the Image</span>
 docker run -P -d tesimg
 docker ps

 ip addr show
 docker ps
</code></pre>
</li>
<li><p>Go to the browser and enter IP_Addr:HostPort</p>
</li>
<li><p>Cleaning up containers and images. This sample Dockerfile I pulled from the internet to test the creation of a Docker container.</p>
</li>
</ol>
<h2 id="heading-learning-microservices-architecture">Learning Microservices Architecture</h2>
<p>I also learned about <strong>Microservices</strong> - what Microservices architecture is, how it is different from the previously used Monolithic architecture. The ideology of <strong>Microservices</strong> is breaking down a monolith into several smaller, self-contained services, each responsible for a specific business functionality. This introduces isolation, loose coupling and flexibility in choosing technology.</p>
<h3 id="heading-communication-methods">Communication Methods:</h3>
<ul>
<li><p><strong>Synchronous</strong> (APIs)</p>
</li>
<li><p><strong>Asynchronous</strong> (Message brokers like RabbitMQ)</p>
</li>
<li><p><strong>Service Mesh</strong></p>
</li>
</ul>
<p>I also explored:</p>
<ul>
<li><strong>Monorepo vs Polyrepo</strong> code strategies</li>
</ul>
<p>Although I stayed on a theoretical level for now, I plan to go deeper with projects soon.</p>
<h2 id="heading-getting-started-with-aws">Getting Started with AWS</h2>
<p>Since cloud was the next big milestone, I turned to AWS Fundamentals. Thankfully, I had some theoretical exposure from a course I took last semester, which helped me understand things quickly.</p>
<h3 id="heading-important-aws-services-for-devops">Important AWS Services for DevOps:</h3>
<p>➡️ Compute: EC2, Lambda, Beanstalk</p>
<p>➡️ Storage: S3, EBS</p>
<p>➡️ Identity: IAM, KMS</p>
<p>➡️ Monitoring: CloudWatch, CloudTrail, X-Ray</p>
<p>➡️ Networking: VPC, ELB, Route53</p>
<p>➡️ Containers: ECS, EKS, ECR</p>
<p>➡️ CI/CD: CodeCommit, CodeBuild, CodeDeploy, CodePipeline</p>
<h2 id="heading-deep-dive-into-ec2-instances">Deep Dive into EC2 Instances</h2>
<p>I created multiple EC2 instances and:</p>
<ul>
<li><p>Played with <strong>Security Groups</strong>, <strong>Key Pairs</strong>, and <strong>Elastic IPs</strong></p>
</li>
<li><p>Hosted a <strong>static HTML page</strong> on an Ubuntu server using Apache2</p>
<p>  <img src="https://docs.aws.amazon.com/images/AWSEC2/latest/UserGuide/images/tutorial-test-instance.png" alt /></p>
</li>
</ul>
<h3 id="heading-aws-cli">AWS CLI:</h3>
<p>Next, I learned about AWS CLI, which lets users interact with AWS services from the terminal. It also helps in automation, scripting, and managing resources via the terminal.</p>
<ul>
<li><p>Installed CLI on my machine</p>
</li>
<li><p>Created an IAM user and configured it with Access Keys</p>
</li>
<li><p>Practiced launching instances, creating key pairs, and security groups via CLI</p>
</li>
</ul>
<h2 id="heading-ebs-volumes-amp-snapshots">EBS Volumes &amp; Snapshots</h2>
<p>Each EC2 instance comes with a block storage volume (EBS). I learned:</p>
<ul>
<li><p>Types of EBS volumes</p>
</li>
<li><p>Creating, attaching, and configuring them</p>
</li>
<li><p>Creating partitions, mounting and unmounting them persistently</p>
</li>
<li><p>Snapshots for backup and restore</p>
</li>
</ul>
<h2 id="heading-load-balancing-with-elb">Load Balancing with ELB</h2>
<p>I created multiple EC2 instances using:</p>
<ul>
<li><p>AMIs and Launch Templates</p>
</li>
<li><p>Hosted a basic HTML page on each</p>
</li>
<li><p>Created <strong>Target Groups</strong> and an <strong>Application Load Balancer (ALB)</strong></p>
</li>
<li><p>Configured listeners and verified load distribution</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744525560502/fb3fb983-4599-4372-8303-8054c4198ce1.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-monitoring-with-cloudwatch-amp-sns-alarms">Monitoring with CloudWatch &amp; SNS Alarms</h2>
<p>I used <strong>CloudWatch</strong> to monitor CPU usage on an EC2 instance and:</p>
<ul>
<li><p>Created <strong>SNS Topic</strong> and Subscription</p>
</li>
<li><p>Configured <strong>Alarms</strong> to notify me via <strong>email</strong> or <strong>SMS</strong></p>
</li>
</ul>
<p>Faced some issues with email alerts, but SMS notifications worked as expected.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744525595864/0a2afb66-820b-4bd0-85ba-dec215128205.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744526794464/5390e2bc-47f3-438d-b451-00215566f7d1.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-resources-i-used">Resources I Used</h2>
<ol>
<li><p><a target="_blank" href="https://docs.docker.com/get-started/docker-overview/">Docker Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/rv4LlmLmVWk?si=yIy-ufm-ksWSb5tv">Microservices | Techworld with Nana</a></p>
</li>
<li><p><a target="_blank" href="https://aws.amazon.com/what-is-cloud-computing/">AWS | Cloud Computing</a></p>
</li>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/cli/latest/reference/">AWS CLI | Command References</a></p>
</li>
</ol>
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p><strong>1️⃣ Microservices Mini Project Not Working</strong></p>
<ul>
<li>After learning the basics of microservices, I tried building a small demo project using a sample <code>docker-compose.yml</code> file I found online. My goal was to spin up a few lightweight containers as independent services inside a VM. However, the setup consistently failed to build and run. Even after debugging the Dockerfile, checking for dependency issues, and validating port configurations, I couldn’t get the containers running inside the VM. I eventually paused the project and plan to revisit it later with a more hands-on guide.</li>
</ul>
<p><strong>2️⃣ Security Group Misconfiguration for SSH</strong></p>
<ul>
<li>While working with EC2 instances, I created a new instance and configured the inbound rules via the security group to allow SSH access. However, every time I tried to log in using my key pair, I received a "Permission denied" error. I temporarily opened the rule to allow SSH from all IPs (<code>0.0.0.0/0</code>), and it worked. But that’s not a secure long-term solution. I terminated the instance, recreated it with the exact same rule settings and, surprisingly, this time, SSH worked perfectly. Still unsure what caused the initial misbehavior.</li>
</ul>
<p><strong>3️⃣ CloudWatch Alarm Emails Not Delivering</strong></p>
<ul>
<li>I wanted to test CPU utilization monitoring and email alerts using AWS CloudWatch. After configuring everything, the alarm triggered correctly, but I wasn’t receiving emails. The SNS subscription for my email kept showing as "Pending Confirmation" despite confirming multiple times. After researching, I suspected my email address might be on AWS SES's suppression list. As a workaround, I created a new subscription using the <strong>SMS protocol</strong> and tested it using my mobile number - which worked flawlessly. Still need to confirm what happened to my email with AWS support, or try a different email next time.</li>
</ul>
<h2 id="heading-whats-next">What's Next?</h2>
<p>Before exams hit, I plan to:</p>
<ul>
<li><p>Learn <strong>EFS</strong>, <strong>Auto Scaling Groups</strong>, and <strong>S3</strong></p>
</li>
<li><p><strong>Revise</strong> previously covered concepts</p>
</li>
</ul>
<h2 id="heading-lets-connect">Let’s Connect!</h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/">My LinkedIn</a></p>
<p>🔗 <a target="_blank" href="https://github.com/akshansh029">My GitHub</a></p>
<p>If you have any helpful resources or better ways to solve the challenges I faced, or just want to chat about DevOps, drop a comment!</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[From Typing Tests to Vagrant Machines]]></title><description><![CDATA[Introduction
Hello there! It's been a while. I'm really sorry for not uploading anything for the past 3 weeks — life got a little hectic due to a hackathon our team participated in, mid-semester exams, and some other personal stuff. But I’ve promised...]]></description><link>https://blog.akshanshsingh.com/from-typing-tests-to-vagrant-machines</link><guid isPermaLink="true">https://blog.akshanshsingh.com/from-typing-tests-to-vagrant-machines</guid><category><![CDATA[Devops]]></category><category><![CDATA[learning]]></category><category><![CDATA[#learning-in-public]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[projects]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sat, 29 Mar 2025 18:12:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743271591346/e748a1d1-7d44-4264-81bb-709d18b7a094.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! It's been a while. I'm really sorry for not uploading anything for the past 3 weeks — life got a little hectic due to a hackathon our team participated in, mid-semester exams, and some other personal stuff. But I’ve promised myself to try my best to stay more consistent from now on.</p>
<p>Despite the packed schedule, I didn’t completely pause my learning. I still managed to: ✅ Build a solo <strong>Web Development project</strong></p>
<p>✅ Learn more about <strong>Build and Package Manager tools</strong></p>
<p>✅ Dive deeper into <strong>Vagrant and Linux servers</strong></p>
<p>✅ Get started with <strong>YAML</strong></p>
<hr />
<h2 id="heading-building-a-typing-speed-test-application">Building a Typing Speed Test Application</h2>
<p>Just before the exams, I was casually testing my typing speed on <strong>MonkeyType</strong>, and as I was completing test after test, I couldn't help but wonder — <em>How exactly is typing speed, raw speed, accuracy, and errors calculated?</em></p>
<p>While I had a rough idea about these parameters, I was curious about the logic behind implementing them. So, I asked ChatGPT how these parameters are calculated, and it gave me a clear explanation of the process.</p>
<p>Excited, I decided to put this into practice by building a simple <strong>Typing Speed Test</strong> as a single-page application. I implemented:</p>
<ul>
<li><p>Logic to generate random words.</p>
</li>
<li><p>Display the generated words to the user.</p>
</li>
<li><p>Allow the user to type in an input box.</p>
</li>
<li><p>Check each character typed against the generated words.</p>
</li>
<li><p>Highlight errors by displaying wrong characters in <strong>red</strong>.</p>
</li>
<li><p>Calculate typing speed dynamically.</p>
</li>
</ul>
<h3 id="heading-improving-the-application">Improving the Application</h3>
<p>While testing, I noticed that I had to <strong>refresh the page</strong> every time I wanted to try a new test, which was quite annoying. So, I added a <strong>restart button</strong> to reset the test without refreshing.</p>
<p>Then I thought — why stop here?</p>
<p>I went on to:</p>
<ul>
<li><p>Add <strong>raw speed</strong> and <strong>accuracy</strong> calculations.</p>
</li>
<li><p>Integrate a <strong>results section</strong> with a graph.</p>
</li>
<li><p>Create <strong>settings</strong> to change:</p>
<ul>
<li><p>Font size</p>
</li>
<li><p>Font family</p>
</li>
<li><p>Enable/disable typing sounds</p>
</li>
</ul>
</li>
<li><p>Implement <strong>user authentication</strong> (which turned out to be challenging).</p>
</li>
<li><p>Develop a <strong>leaderboard</strong>.</p>
</li>
<li><p>Build an <strong>about page</strong>.</p>
</li>
</ul>
<p>This turned into my <strong>first solo full-stack web development project</strong> after a long time!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743271656084/af967963-1cf5-44e2-b690-e3d5b326f6a8.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-tech-stack-used">Tech Stack Used:</h3>
<ul>
<li><p><strong>Next.js</strong></p>
</li>
<li><p><strong>TailwindCSS</strong></p>
</li>
<li><p><strong>NextAuth</strong></p>
</li>
<li><p><strong>Prisma</strong></p>
</li>
<li><p><strong>PostgreSQL</strong></p>
</li>
<li><p><strong>Shadcn UI</strong></p>
</li>
<li><p><strong>Vercel</strong> (for deployment)</p>
</li>
</ul>
<p>➡️ Check out the GitHub repository here: <a target="_blank" href="https://github.com/Akshansh029/TypeFlow">TypeFlow Repo</a></p>
<hr />
<h2 id="heading-continuing-devops-learning-build-amp-package-manager-tools">Continuing DevOps Learning: Build &amp; Package Manager Tools</h2>
<p>After completing my web project, I resumed my <strong>DevOps journey</strong>.</p>
<p>Previously, I had learned to build <strong>Java applications</strong> using <strong>Gradle</strong>. This time, I expanded my knowledge by:</p>
<ul>
<li><p>Learning how to build Python projects using <strong>setuptools</strong>.</p>
</li>
<li><p>Setting up a <code>setup.py</code> file.</p>
</li>
<li><p>Understanding what a <strong>wheel (.whl)</strong> file is.</p>
</li>
<li><p>Exploring <strong>NPM</strong> for JavaScript projects.</p>
</li>
<li><p>Understanding the <strong>build process</strong> of JS applications.</p>
</li>
<li><p>Differentiating between a <strong>Library</strong>, <strong>Package</strong>, and <strong>Framework</strong>.</p>
</li>
</ul>
<hr />
<h2 id="heading-deep-dive-into-vagrant-amp-linux-servers">Deep Dive into Vagrant &amp; Linux Servers</h2>
<p>I had earlier used Vagrant briefly to create a VM when I first started with Linux. This time, I took it a step further.</p>
<p>I learned how to:</p>
<ul>
<li><p>Configure Vagrant using a VagrantFile:</p>
<ul>
<li><p>Choose which Vagrant Box (OS) to use.</p>
</li>
<li><p>Allocate RAM and CPUs.</p>
</li>
<li><p>Automate provisioning.</p>
</li>
</ul>
</li>
<li><p>Create Synced Folders:</p>
<ul>
<li>Share files between the host machine and the virtual machine.</li>
</ul>
</li>
</ul>
<h3 id="heading-small-projects-to-practice">Small Projects to Practice:</h3>
<p>1️⃣ Hosted a basic HTML template inside a VM.<br />2️⃣ Hosted a WordPress configuration setup for blogging inside a VM.</p>
<p>For both:</p>
<ul>
<li><p>First, I performed all steps <strong>manually</strong> to fully understand each action.</p>
</li>
<li><p>Then, I <strong>automated</strong> the entire setup using <strong>VagrantFile</strong> so that when the VM boots, everything is ready automatically.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743271676212/18fbc7e9-af7d-42b6-9a30-0643d24e851e.png" alt class="image--center mx-auto" /></p>
<p>This helped me get hands-on with:</p>
<ul>
<li><p>Provisioning</p>
</li>
<li><p>Service management</p>
</li>
<li><p>Hosting applications</p>
</li>
</ul>
<p>I also explored how to provision Multi-VM setups using a single VagrantFile. This was something I had been curious about, and accomplishing it felt rewarding.</p>
<hr />
<h2 id="heading-getting-started-with-yaml">Getting Started with YAML</h2>
<p>Today, I finally got started with <strong>YAML</strong> — a human-readable data serialization language, just like XML and JSON.</p>
<h3 id="heading-what-is-data-serialization">What is Data Serialization?</h3>
<p>Serialization is the process of converting data structures into a <strong>standard format</strong> so that they can be transferred between applications or services.</p>
<h3 id="heading-what-i-learned">What I Learned:</h3>
<ul>
<li><p>Basic syntax of YAML.</p>
</li>
<li><p>Declaring various data types and structures.</p>
</li>
<li><p>Writing real-world examples like an Nginx web server configuration.</p>
</li>
</ul>
<h3 id="heading-sample-yaml-example">Sample YAML Example:</h3>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>            <span class="hljs-comment"># API version used</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>               <span class="hljs-comment"># The type of Kubernetes object</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">nginx-deployment</span>       <span class="hljs-comment"># Name of the deployment</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">nginx</span>                 <span class="hljs-comment"># Label assigned to this deployment</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">replicas:</span> <span class="hljs-number">3</span>                  <span class="hljs-comment"># Number of pod replicas</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">app:</span> <span class="hljs-string">nginx</span>               <span class="hljs-comment"># Must match pod labels</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">metadata:</span>
      <span class="hljs-attr">labels:</span>
        <span class="hljs-attr">app:</span> <span class="hljs-string">nginx</span>             <span class="hljs-comment"># Label assigned to pods created by this deployment</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">containers:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">nginx</span>          <span class="hljs-comment"># Container name</span>
          <span class="hljs-attr">image:</span> <span class="hljs-string">nginx:latest</span>  <span class="hljs-comment"># Docker image</span>
          <span class="hljs-attr">ports:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">containerPort:</span> <span class="hljs-number">80</span> <span class="hljs-comment"># Port exposed inside the container</span>
</code></pre>
<hr />
<h2 id="heading-resources-i-used">Resources I Used</h2>
<ol>
<li><p><a target="_blank" href="https://ubuntu.com/tutorials/install-and-configure-wordpress#1-overview"><strong>Install and Configure WordPress | Ubuntu</strong></a></p>
</li>
<li><p><a target="_blank" href="https://developer.hashicorp.com/vagrant/docs/vagrantfile"><strong>VagrantFile | Vagrant | HashiCorp Developer Docs</strong></a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/1uFVr15xDGg?si=n2YAKyR4PDKsRnRk"><strong>YAML Tutorial | TechWorld with Nana</strong></a></p>
</li>
</ol>
<p>(Note: This does not include resources I used for the web development project.)</p>
<hr />
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p>1️⃣ <strong>Authentication Struggle</strong></p>
<p>Initially, I wanted to learn and use <strong>Supabase</strong> as my database and authentication system. However, I found it difficult to work with and eventually dropped it.</p>
<p>✅ <strong>Solution</strong>: Switched to <strong>NextAuth</strong> for authentication and used <strong>NeonDB</strong> instead of Supabase.</p>
<p>2️⃣ <strong>Provisioning WordPress Setup</strong></p>
<p>I couldn't get the <strong>WordPress</strong> setup provisioned correctly at first.</p>
<p>✅ <strong>Solution</strong>: Restarted the whole process and fixed some typographical mistakes which solved the problem.</p>
<hr />
<h2 id="heading-whats-next">What’s Next?</h2>
<ul>
<li><p>Build a project where I actually <strong>use YAML</strong> in a real-world scenario.</p>
</li>
<li><p>Get started with <strong>Containers</strong>.</p>
</li>
</ul>
<hr />
<h2 id="heading-lets-connect">Let’s Connect!</h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/">My LinkedIn</a></p>
<p>🔗 <a target="_blank" href="https://github.com/Akshansh029">My GitHub</a></p>
<p>If you have any recommended resources, better approaches to the challenges I faced, or just want to share some insights — I'd love to hear from you! Drop your thoughts in the comments.</p>
]]></content:encoded></item><item><title><![CDATA[Exploring Makefiles, SSH, and Gradle]]></title><description><![CDATA[Introduction
Hello there! 👋 This past week marked the fourth week of my DevOps journey. While I was a bit inconsistent and sluggish, I still managed to learn some exciting and essential concepts. Initially, my plan was to start learning Python, but ...]]></description><link>https://blog.akshanshsingh.com/exploring-makefiles-ssh-and-gradle</link><guid isPermaLink="true">https://blog.akshanshsingh.com/exploring-makefiles-ssh-and-gradle</guid><category><![CDATA[Devops]]></category><category><![CDATA[Learning Journey]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sat, 01 Mar 2025 11:38:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740829048933/e07df640-aaf8-4b33-82f1-0a71fceed829.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! 👋 This past week marked the <strong>fourth week</strong> of my DevOps journey. While I was a bit inconsistent and sluggish, I still managed to learn some exciting and essential concepts. Initially, my plan was to start learning Python, but I realized it would be better to push it down the roadmap and focus on some other important tools first.</p>
<p>This week, I:<br />- <strong>Completed another mini Bash scripting project</strong><br /><strong>- Learned about Makefiles</strong><br /><strong>- Explored SSH login &amp; SSH keys</strong><br /><strong>- Dived into advanced Git features</strong><br /><strong>- Revised API development in Next.js</strong><br /><strong>- Started learning Build Tools, mainly Gradle</strong></p>
<p>I'll share everything I learned, the resources I used, and the challenges I faced. Let's get started.</p>
<hr />
<h2 id="heading-automating-aws-s3-bucket-creation-with-bash"><strong>Automating AWS S3 Bucket Creation with Bash</strong></h2>
<p>Last week, I completed a mini project in which I wrote a script to create an <strong>EC2 instance</strong> on AWS and automate the AWS configuration. Although I modified the script and learned a lot, I wanted to build something similar but completely on my own.</p>
<p>So, I decided to write a <strong>Bash script to create an S3 bucket</strong> with default configurations on AWS. I reused some functions from my previous EC2 script, such as AWS CLI installation, and then searched for AWS CLI commands to create an S3 bucket.</p>
<h3 id="heading-creating-an-s3-bucket"><strong>Creating an S3 Bucket</strong></h3>
<p>The commands for creating an S3 bucket were simpler compared to EC2 instance creation. Here’s the function I wrote:</p>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">create_s3_bucket</span></span>() {
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Creating S3 bucket with default name as 'shell-scripting-demo'..."</span>
    BUCKET_NAME=<span class="hljs-string">"shell-scripting-demo"</span>

    aws s3 mb s3://<span class="hljs-variable">$BUCKET_NAME</span> --region <span class="hljs-variable">$AWS_DEFAULT_REGION</span>

    <span class="hljs-keyword">if</span> aws s3api head-bucket --bucket <span class="hljs-string">"<span class="hljs-variable">$BUCKET_NAME</span>"</span> 2&gt;/dev/null; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"S3 bucket created successfully!"</span>
    <span class="hljs-keyword">else</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"There was an error creating S3 bucket, exiting the process..."</span>
        <span class="hljs-built_in">exit</span> 1
    <span class="hljs-keyword">fi</span>
}
</code></pre>
<h3 id="heading-copying-an-item-into-the-s3-bucket"><strong>Copying an Item into the S3 Bucket</strong></h3>
<p>To add more challenge, I also wrote a function to <strong>upload a sample file</strong> to the newly created bucket:</p>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">copy_item_in_bucket</span></span>() {
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Copying sample item to S3 bucket..."</span>
    <span class="hljs-built_in">local</span> ITEM=<span class="hljs-string">"/home/vagrant/DevOps-Learning/shell-scripting/script-projects/todo.txt"</span>

    aws s3 cp <span class="hljs-variable">$ITEM</span> s3://<span class="hljs-variable">$BUCKET_NAME</span>

    <span class="hljs-built_in">local</span> KEY=$(aws s3api list-objects-v2 --bucket <span class="hljs-variable">$BUCKET_NAME</span> --query <span class="hljs-string">"sort_by(Contents, &amp;LastModified)[-1].Key"</span> --output text)

    <span class="hljs-keyword">if</span> [ -n <span class="hljs-string">"<span class="hljs-variable">$KEY</span>"</span> ]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"Item copied successfully! Bucket name: <span class="hljs-variable">$BUCKET_NAME</span> S3 item Key: <span class="hljs-variable">$KEY</span>"</span>
    <span class="hljs-keyword">else</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"Item couldn't be copied to <span class="hljs-variable">$BUCKET_NAME</span> bucket"</span>
        <span class="hljs-built_in">return</span> 1
    <span class="hljs-keyword">fi</span>
}
</code></pre>
<p>One tricky part was <strong>checking whether the item was successfully copied</strong>. Initially, I used the prefix keyword, but it was prone to errors as multiple files could have the same starting name (as mentioned on Stack Overflow). Using the <strong>last modified sorting</strong> provided a better approach.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740827835370/e2cbc8ea-4a05-414c-ab86-b8a661d65dbb.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-learning-makefiles"><strong>Learning Makefiles</strong></h2>
<p>After completing my mini Bash scripting project, I started learning about <strong>Makefiles</strong>. I had briefly encountered them during my <strong>Linux fundamentals</strong>, but I hadn't explored them in depth.</p>
<h3 id="heading-what-is-a-makefile"><strong>What is a Makefile?</strong></h3>
<p>A <strong>Makefile</strong> is a simple text file that controls a project's build process. It is used to automate tasks in C, C++, and many other languages.</p>
<h3 id="heading-why-use-makefiles"><strong>Why Use Makefiles?</strong></h3>
<ul>
<li><p><strong>Automates repetitive tasks</strong> like compiling code, running tests, and installing dependencies.</p>
</li>
<li><p><strong>Simplifies command execution</strong> by defining custom rules.</p>
</li>
<li><p><strong>Speeds up builds</strong> by recompiling only changed files.</p>
</li>
</ul>
<p>I explored the syntax and practiced by creating a simple Makefile to automate a small workflow.</p>
<hr />
<h2 id="heading-exploring-ssh-amp-ssh-keys"><strong>Exploring SSH &amp; SSH Keys</strong></h2>
<p>When I first learned Linux fundamentals, I didn’t fully grasp SSH (Secure Shell), so I revisited it this week. <strong>SSH</strong> is a protocol used for secure remote server access, file transfers, and system administration.</p>
<p>To practice SSH, I created an EC2 instance to simulate a remote server.</p>
<h3 id="heading-methods-to-login-into-a-remote-server-i-learned"><strong>Methods to Login into a Remote Server I learned:</strong></h3>
<p>1️⃣ <strong>Password Authentication</strong><br />2️⃣ <strong>SSH Keys</strong></p>
<h3 id="heading-generating-an-ssh-key-pair"><strong>Generating an SSH Key Pair</strong></h3>
<p>The <strong>SSH key method</strong> doesn’t require passwords. Here’s how I generated an SSH key pair:</p>
<pre><code class="lang-bash">ssh-keygen -t rsa -b 4096
</code></pre>
<ul>
<li><p>This command creates two keys: a <strong>public key</strong> (stored on the server) and a <strong>private key</strong> (stored on the client).</p>
</li>
<li><p>To log in, the public key is matched with the private key using:</p>
</li>
</ul>
<pre><code class="lang-bash">ssh user@host_ip_addr
</code></pre>
<p>This ensures secure authentication without requiring passwords.</p>
<hr />
<h2 id="heading-getting-started-with-gradle-amp-advanced-git-features"><strong>Getting Started with Gradle &amp; Advanced Git Features</strong></h2>
<p>I took some time to understand what build tools are and why they are essential in software development. Build tools help automate the process of transforming source code into executable applications by handling tasks like:</p>
<ul>
<li><p><strong>Compiling</strong>: Converting source code (C, Java, etc.) into machine code or bytecode.</p>
</li>
<li><p><strong>Linking</strong>: Combining multiple compiled files into a single executable.</p>
</li>
<li><p><strong>Dependency Management</strong>: Ensuring all required libraries are available.</p>
</li>
<li><p><strong>Testing &amp; Packaging</strong>: Running unit tests and packaging the application for distribution.</p>
</li>
</ul>
<h3 id="heading-common-build-tools"><strong>Common Build Tools</strong></h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Build Tool</td><td>Used For</td><td>Language</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Make</strong></td><td>Automating builds</td><td>C, C++</td></tr>
<tr>
<td><strong>Maven</strong></td><td>Dependency &amp; project management</td><td>Java</td></tr>
<tr>
<td><strong>Gradle</strong></td><td>Faster, flexible builds</td><td>Java, Kotlin</td></tr>
<tr>
<td><strong>Bazel</strong></td><td>Scalable builds</td><td>Multi-language</td></tr>
<tr>
<td><strong>Ant</strong></td><td>XML-based build automation</td><td>Java</td></tr>
</tbody>
</table>
</div><p>After understanding these concepts, I started with one of the most popular build tools for Java—<strong>Gradle</strong>.</p>
<p>I started with Gradle, one of the popular build tools for Java, Android, and Kotlin projects. I explored:<br />→ <strong>Gradle Project Structure</strong> - Understanding files and directories in a basic project.<br />→ <strong>Gradle Tasks &amp; Wrapper</strong> - How automation works within a Gradle project.<br />→ <strong>Running a small Java application using Gradle.</strong></p>
<p>To practice, I got the code of a Java project that prints "Hello" or "Hola" based on an argument. I initially did all this on my <strong>Ubuntu dual-boot setup</strong>, but I ran into system crashes and memory issues, even though I had allocated 20GB of space. Eventually, I had to remove Ubuntu and switch back to Windows.</p>
<p>After tackling the basics of Gradle, I spent a few hours learning <strong>advanced Git features</strong> like:</p>
<ul>
<li><p><strong>Interactive Rebase</strong></p>
</li>
<li><p><strong>Reflog</strong></p>
</li>
<li><p><strong>Search &amp; Find</strong></p>
</li>
<li><p><strong>Submodules</strong></p>
</li>
<li><p><strong>Cherry-picking</strong></p>
</li>
</ul>
<p>Since I had been focused on DevOps, I hadn't done much Web Development recently. To refresh my skills, I revised <strong>API development in Next.js</strong>, covering:</p>
<ul>
<li><p><strong>CRUD operations</strong></p>
</li>
<li><p><strong>Query parameters</strong></p>
</li>
<li><p><strong>Dynamic routes</strong></p>
</li>
<li><p><strong>Middleware concepts</strong></p>
</li>
</ul>
<hr />
<h2 id="heading-resources-i-used-this-week">Resources I used this week-</h2>
<ol>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/cli/latest/reference/s3api/create-bucket.html">AWS CLI Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/adelarsq/awesome-make">Awesome Make GitHub Repo</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/YS5Zh7KExvE?si=dSJr89sY7QSO4DaO">Learn Linux TV | OpenSSH Tutorial</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/R6Z-Sxb837I?si=qgUJOVgxHq5Y0xaF">Tom Gregory | Gradle Tutorial</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/qsTthZi23VE?si=WPM1yRG4Cz9DDmTd">freecodecamp Advanced Git Tutorial</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/aEFkWxUNAVc?si=SbPfDxAVOu-EVNJA">freecodecamp | Rest APIs with Next.js 14</a></p>
</li>
</ol>
<hr />
<h2 id="heading-challenges-i-faced-this-week"><strong>Challenges I Faced This Week</strong></h2>
<p>1️⃣ <strong>Checking if an Item Was Copied in an S3 Bucket</strong></p>
<ul>
<li><p><strong>Issue:</strong> Initial method using prefix keyword was unreliable.</p>
</li>
<li><p><strong>Solution:</strong> Used last modified sorting for accuracy.</p>
</li>
</ul>
<p>2️⃣ <strong>SSH Login Issues</strong></p>
<ul>
<li><p><strong>Issue:</strong> <code>ssh username@server_ip</code> was failing despite enabling PasswordAuthentication.</p>
</li>
<li><p><strong>Solution:</strong> Couldn’t find a solution, so I switched to SSH keys, which worked perfectly.</p>
</li>
</ul>
<p>3️⃣ <strong>Ubuntu Performance Issues</strong></p>
<ul>
<li><p><strong>Issue:</strong> Ubuntu wasn’t running smoothly, even with 20GB allocated space.</p>
</li>
<li><p><strong>Solution:</strong> Couldn’t find a way to increase disk space, so I removed Ubuntu and switched back to Windows.</p>
</li>
</ul>
<hr />
<h2 id="heading-whats-next"><strong>What’s Next?</strong></h2>
<p>Next week, I plan to:<br />✅ <strong>Explore more Build Tools &amp; Package Managers</strong><br />✅ <strong>Learn about Artifacts &amp; Artifact Repository Management</strong></p>
<hr />
<h2 id="heading-lets-connect"><strong>Let’s Connect!</strong></h2>
<p>🔗 <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/">My LinkedIn</a> 🔗 <a target="_blank" href="https://github.com/Akshansh029"><strong>My GitHub</strong></a></p>
<p>If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I’d love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Networking Deep Dive & Bash Scripting Adventures]]></title><description><![CDATA[Introduction
Hello there! 👋 This past week marked the third week of my DevOps journey, and it has been an exciting and challenging one. I dived deep into how DNS works, the TCP/IP model, Bash scripting, and built some projects along the way. I also ...]]></description><link>https://blog.akshanshsingh.com/networking-deep-dive-and-bash-scripting-adventures</link><guid isPermaLink="true">https://blog.akshanshsingh.com/networking-deep-dive-and-bash-scripting-adventures</guid><category><![CDATA[Devops]]></category><category><![CDATA[#learning-in-public]]></category><category><![CDATA[Learning Journey]]></category><category><![CDATA[Bash]]></category><category><![CDATA[networking]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Fri, 21 Feb 2025 19:31:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740165650947/a5b5ab5d-eea1-4e45-a0a7-81f231f7ffa9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! 👋 This past week marked the <strong>third week</strong> of my DevOps journey, and it has been an <strong>exciting and challenging</strong> one. I dived deep into <strong>how DNS works, the TCP/IP model, Bash scripting, and built some projects along the way</strong>. I also faced my fair share of errors (as expected), but overcoming them was a great learning experience. Let's go through each topic in detail!</p>
<hr />
<h2 id="heading-exploring-the-depths-of-networking">Exploring the Depths of Networking</h2>
<p>Last week, I covered the <strong>basics of computer networks</strong>, including the OSI model and network topologies. This week, I explored:</p>
<h3 id="heading-1-how-dns-works"><strong>1. How DNS Works</strong></h3>
<p>The <strong>Domain Name System (DNS)</strong> is what helps map <strong>human-readable domain names (like</strong> <a target="_blank" href="http://google.com"><strong>google.com</strong></a><strong>)</strong> to <strong>IP addresses</strong> that machines understand. Learning about DNS helped me understand:</p>
<ul>
<li><p>The role of <strong>DNS resolvers, root servers, TLD servers, and authoritative name servers</strong>.</p>
</li>
<li><p>How requests flow when a user enters a URL in the browser.</p>
<p>  <img src="https://cf-assets.www.cloudflare.com/slt3lc6tev37/1NzaAqpEFGjqTZPAS02oNv/bf7b3f305d9c35bde5c5b93a519ba6d5/what_is_a_dns_server_dns_lookup.png" alt="What is DNS? | How DNS works | Cloudflare" /></p>
</li>
</ul>
<h3 id="heading-2-tcpip-model"><strong>2. TCP/IP Model</strong></h3>
<p>Unlike the <strong>theoretical OSI model</strong>, the <strong>TCP/IP model</strong> is the real-world networking framework we use every day. It consists of the following layers: 1️⃣ <strong>Network Access Layer (Link Layer)</strong> – Deals with physical transmission of data.</p>
<p>2️⃣ <strong>Internet Layer</strong> – Responsible for addressing and routing packets using protocols like IP.</p>
<p>3️⃣ <strong>Transport Layer</strong> – Manages end-to-end communication using protocols like TCP and UDP.</p>
<p>4️⃣ <strong>Application Layer</strong> – Interfaces with user applications like HTTP, SMTP, and FTP.</p>
<p>Some resources describe the TCP/IP model as <strong>5 layers</strong>, merging the <strong>Data Link Layer and Physical Layer</strong> into one. Learning about this model made it easier for me to grasp how <strong>data packets travel across networks</strong> and how <strong>routing</strong> works.</p>
<p><img src="https://media.geeksforgeeks.org/wp-content/uploads/20230417045622/OSI-vs-TCP-vs-Hybrid-2.webp" alt="TCP/IP and OSI" /></p>
<h3 id="heading-3-forward-and-reverse-proxy"><strong>3. Forward and Reverse Proxy</strong></h3>
<p>I also explored <strong>proxy servers</strong> and how they act as intermediaries between clients and the internet:</p>
<ul>
<li><p><strong>Forward Proxy:</strong> Sits between the client and the web, helping in <strong>hiding identity, caching content, and filtering traffic</strong>.</p>
</li>
<li><p><strong>Reverse Proxy:</strong> Sits between the web server and users, mainly used for <strong>load balancing, security, and caching</strong>.</p>
</li>
</ul>
<p>A widely used example of a <strong>Reverse Proxy</strong> is <strong>Nginx</strong>, which I plan to explore in-depth soon.</p>
<h3 id="heading-resources-i-used-for-networking"><strong>Resources I Used for Networking:</strong></h3>
<ol>
<li><p><a target="_blank" href="https://youtu.be/IPvYjXCsTg8?si=dpAkoN1Ga3KAYsIA">Networking Basics - YouTube</a></p>
</li>
<li><p><a target="_blank" href="https://www.geeksforgeeks.org/domain-name-system-dns-in-application-layer/">GeeksforGeeks - DNS System</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/2QGgEk20RXM?si=H8BKfs9BN5zI9p3g">TCP/IP Explained - YouTube</a></p>
</li>
</ol>
<hr />
<h2 id="heading-getting-started-with-bash-scripting">Getting Started with Bash Scripting</h2>
<p>After wrapping up Networking, I jumped into <strong>Bash scripting</strong>. The first thing I did was understand <strong>what Bash is and how it differs from other shells</strong>. Then, I got hands-on by writing my first script:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
<span class="hljs-comment"># My first Bash script</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"This is my first script as a DevOps Student"</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Lionel Andres Messi"</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"GOAT"</span>
</code></pre>
<p>A bit embarrassing, but let's move past that. 😅</p>
<p>I then learned about:</p>
<ul>
<li><p><strong>Variables &amp; Comments</strong></p>
</li>
<li><p><strong>If statements &amp; Loops</strong></p>
</li>
<li><p><strong>Exit Codes &amp; Functions</strong></p>
</li>
<li><p><strong>Command-line arguments &amp; Case statements</strong></p>
</li>
</ul>
<p>To <strong>practice Bash scripting</strong>, I built some small projects like:<br />✅ <strong>A simple to-do list script</strong> that adds tasks to a file.<br />✅ <strong>A basic calculator script</strong> for performing arithmetic operations.</p>
<h3 id="heading-first-project-deploying-a-django-app-using-docker-amp-nginx"><strong>First Project: Deploying a Django App using Docker &amp; Nginx</strong></h3>
<p>Even though I had no prior experience with <strong>Docker and Nginx</strong>, I followed along with a tutorial where the instructor explained each script, ran it, and debugged errors. But while following the tutorial, I encountered an unexpected <strong>error</strong>:</p>
<pre><code class="lang-plaintext">error checking context: no permission to read from '/home/vagrant/DevOps-Learning/shell-scripting/script-projects/django-notes-app/data/mysql/db/#ib_16384_0.dblwr'
Failed to build and deploy the app.
</code></pre>
<p><strong>Solution:</strong></p>
<ul>
<li><p>The error occurred because <strong>Docker didn’t have permission to access the MySQL folder</strong> in the cloned repo.</p>
</li>
<li><p>I used the <code>chown</code> command to <strong>give the current user ownership</strong> of the folder.</p>
</li>
<li><p>Then, I modified the <strong>permissions</strong> of the cloned repo.</p>
</li>
</ul>
<p>This allowed me to <strong>successfully deploy the app using Docker Compose &amp; Nginx</strong>. However, since I was running my Ubuntu machine in a <strong>VM</strong>, I couldn't access <code>localhost:8000</code> directly. Instead, I checked my VM’s IP using <code>ip addr show</code> and accessed the port via that IP.</p>
<hr />
<h3 id="heading-second-project-creating-an-aws-ec2-instance-using-bash"><strong>Second Project: Creating an AWS EC2 Instance using Bash</strong></h3>
<p>This project aimed to <strong>automate the process of creating an AWS EC2 instance using Bash scripting</strong>. I was particularly excited about this project as it gave me a <strong>real-world perspective on automation and infrastructure provisioning</strong>.</p>
<h3 id="heading-step-1-checking-aws-cli-installation"><strong>Step 1: Checking AWS CLI Installation</strong></h3>
<p>Before proceeding with creating an instance, I needed to ensure that <strong>AWS CLI</strong> was installed. To check this, I wrote the following function:</p>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">check_awscli</span></span>() {
    <span class="hljs-keyword">if</span> ! <span class="hljs-built_in">command</span> -v aws &amp;&gt; /dev/null; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"AWS CLI is not installed. Installing it now..."</span> &gt;&amp;2
        <span class="hljs-built_in">return</span> 1
    <span class="hljs-keyword">fi</span>
}
</code></pre>
<p>If AWS CLI wasn’t installed, I wanted the script to handle the installation automatically.</p>
<h3 id="heading-step-2-installing-aws-cli"><strong>Step 2: Installing AWS CLI</strong></h3>
<p>To automate the installation of AWS CLI on a Linux system, I wrote this function:</p>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">install_awscli</span></span>() {
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Installing AWS CLI v2 on Linux..."</span>

    <span class="hljs-comment"># Download and install AWS CLI v2</span>
    curl <span class="hljs-string">"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"</span> -o <span class="hljs-string">"awscliv2.zip"</span>
    sudo apt-get install -y unzip &amp;&gt; /dev/null
    unzip awscliv2.zip
    sudo ./aws/install

    <span class="hljs-comment"># Verify installation</span>
    aws --version || {
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"AWS CLI installation failed. Please install manually."</span>
        <span class="hljs-built_in">exit</span> 1
    }

    <span class="hljs-comment"># Clean up</span>
    rm -rf awscliv2.zip ./aws

    <span class="hljs-built_in">echo</span> <span class="hljs-string">"AWS CLI Installation Completed."</span>
}
</code></pre>
<p>This function <strong>downloads and installs AWS CLI</strong>, verifies the installation, and cleans up unnecessary files.</p>
<h3 id="heading-step-3-creating-the-ec2-instance"><strong>Step 3: Creating the EC2 Instance</strong></h3>
<p>Once AWS CLI was installed, I wrote a function to <strong>create an EC2 instance using AWS CLI commands</strong>:</p>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">create_ec2_instance</span></span>() {
    <span class="hljs-built_in">local</span> ami_id=<span class="hljs-string">"<span class="hljs-variable">$1</span>"</span>
    <span class="hljs-built_in">local</span> instance_type=<span class="hljs-string">"<span class="hljs-variable">$2</span>"</span>
    <span class="hljs-built_in">local</span> key_name=<span class="hljs-string">"<span class="hljs-variable">$3</span>"</span>
    <span class="hljs-built_in">local</span> subnet_id=<span class="hljs-string">"<span class="hljs-variable">$4</span>"</span>
    <span class="hljs-built_in">local</span> security_group_ids=<span class="hljs-string">"<span class="hljs-variable">$5</span>"</span>
    <span class="hljs-built_in">local</span> instance_name=<span class="hljs-string">"<span class="hljs-variable">$6</span>"</span>

    <span class="hljs-comment"># Run AWS CLI command to create EC2 instance</span>
    instance_id=$(aws ec2 run-instances \
        --image-id <span class="hljs-string">"<span class="hljs-variable">$ami_id</span>"</span> \
        --instance-type <span class="hljs-string">"<span class="hljs-variable">$instance_type</span>"</span> \
        --key-name <span class="hljs-string">"<span class="hljs-variable">$key_name</span>"</span> \
        --subnet-id <span class="hljs-string">"<span class="hljs-variable">$subnet_id</span>"</span> \
        --security-group-ids <span class="hljs-string">"<span class="hljs-variable">$security_group_ids</span>"</span> \
        --tag-specifications <span class="hljs-string">"ResourceType=instance,Tags=[{Key=Name,Value=<span class="hljs-variable">$instance_name</span>}]"</span> \
        --query <span class="hljs-string">'Instances[0].InstanceId'</span> \
        --output text
    )

    <span class="hljs-keyword">if</span> [[ -z <span class="hljs-string">"<span class="hljs-variable">$instance_id</span>"</span> ]]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"Failed to create EC2 instance."</span> &gt;&amp;2
        <span class="hljs-built_in">exit</span> 1
    <span class="hljs-keyword">fi</span>

    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Instance <span class="hljs-variable">$instance_id</span> created successfully."</span>

    <span class="hljs-comment"># Wait for the instance to be in running state</span>
    wait_for_instance <span class="hljs-string">"<span class="hljs-variable">$instance_id</span>"</span>
}
</code></pre>
<p>This function takes <strong>multiple parameters</strong> such as AMI ID, instance type, key name, subnet ID, security group ID, and instance name. After executing the <strong>AWS CLI command to create an instance</strong>, it waits for the instance to be fully initialized.</p>
<h3 id="heading-step-4-waiting-for-instance-to-run"><strong>Step 4: Waiting for Instance to Run</strong></h3>
<p>Once the EC2 instance is created, the script waits until the instance reaches the <strong>running</strong> state:</p>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">wait_for_instance</span></span>() {
    <span class="hljs-built_in">local</span> instance_id=<span class="hljs-string">"<span class="hljs-variable">$1</span>"</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Waiting for instance <span class="hljs-variable">$instance_id</span> to be in running state..."</span>

    <span class="hljs-keyword">while</span> <span class="hljs-literal">true</span>; <span class="hljs-keyword">do</span>
        state=$(aws ec2 describe-instances --instance-ids <span class="hljs-string">"<span class="hljs-variable">$instance_id</span>"</span> --query <span class="hljs-string">'Reservations[0].Instances[0].State.Name'</span> --output text)
        <span class="hljs-keyword">if</span> [[ <span class="hljs-string">"<span class="hljs-variable">$state</span>"</span> == <span class="hljs-string">"running"</span> ]]; <span class="hljs-keyword">then</span>
            <span class="hljs-built_in">echo</span> <span class="hljs-string">"Instance <span class="hljs-variable">$instance_id</span> is now running."</span>
            <span class="hljs-built_in">break</span>
        <span class="hljs-keyword">fi</span>
        sleep 10
    <span class="hljs-keyword">done</span>
}
</code></pre>
<h3 id="heading-step-5-automating-aws-configuration"><strong>Step 5: Automating AWS Configuration</strong></h3>
<p>A key realization was that <strong>AWS CLI requires manual configuration</strong> before usage, which defeats the purpose of full automation. I discovered that AWS credentials are stored in <strong>.aws/config and .aws/credentials</strong>, so I automated this process:</p>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">configure_aws</span></span>() {
    <span class="hljs-built_in">local</span> aws_access_key=<span class="hljs-string">"<span class="hljs-variable">$AWS_ACCESS_KEY_ID</span>"</span>
    <span class="hljs-built_in">local</span> aws_secret_key=<span class="hljs-string">"<span class="hljs-variable">$AWS_SECRET_ACCESS_KEY</span>"</span>
    <span class="hljs-built_in">local</span> aws_region=<span class="hljs-string">"<span class="hljs-variable">$AWS_DEFAULT_REGION</span>"</span>

    <span class="hljs-comment"># Ensuring the .aws directory exists</span>
    mkdir -p ~/.aws

    cat &gt; ~/.aws/credentials &lt;&lt;EOL
[default]
aws_access_key_id = <span class="hljs-variable">$aws_access_key</span>
aws_secret_access_key = <span class="hljs-variable">$aws_secret_key</span>
EOL

    cat &gt; ~/.aws/config &lt;&lt;EOL
[default]
region = <span class="hljs-variable">$aws_region</span>
output = json
EOL

    <span class="hljs-built_in">echo</span> <span class="hljs-string">"AWS CLI configured successfully."</span>
}
</code></pre>
<p>This function pulls AWS credentials and region information from <strong>environment variables</strong> and writes them into the required configuration files. <strong>This ensures that AWS CLI is ready to use without manual intervention.</strong></p>
<h3 id="heading-step-6-bringing-it-all-together"><strong>Step 6: Bringing It All Together</strong></h3>
<p>Finally, I wrapped everything into a <strong>main function</strong> and executed the script:</p>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">main</span></span>() {
    check_awscli || install_awscli

    configure_aws || {
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"AWS Configuration failed, exiting..."</span>
        <span class="hljs-built_in">exit</span> 1
    }

    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Creating EC2 instance..."</span>

    <span class="hljs-comment"># Specify the parameters for creating the EC2 instance</span>
    AMI_ID=<span class="hljs-string">"ami-04b4f1a9cf54c11d0"</span>
    INSTANCE_TYPE=<span class="hljs-string">"t2.micro"</span>
    KEY_NAME=<span class="hljs-string">"<span class="hljs-variable">$AWS_KEY_NAME</span>"</span>
    SUBNET_ID=<span class="hljs-string">"<span class="hljs-variable">$AWS_SUBNET_ID</span>"</span>
    SECURITY_GROUP_IDS=<span class="hljs-string">"<span class="hljs-variable">$AWS_SECURITY_GROUP_IDS</span>"</span>
    INSTANCE_NAME=<span class="hljs-string">"Shell-Script-EC2-Demo"</span>

    <span class="hljs-comment"># Call the function to create the EC2 instance</span>
    create_ec2_instance <span class="hljs-string">"<span class="hljs-variable">$AMI_ID</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$INSTANCE_TYPE</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$KEY_NAME</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$SUBNET_ID</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$SECURITY_GROUP_IDS</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$INSTANCE_NAME</span>"</span>

    <span class="hljs-built_in">echo</span> <span class="hljs-string">"EC2 instance creation completed."</span>
}

main <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span>
</code></pre>
<p>After writing and testing this script, I was <strong>thrilled to see everything working smoothly on the first run!</strong> This was a <strong>huge confidence booster</strong> as I managed to:</p>
<ul>
<li><p><strong>Automate the installation of AWS CLI</strong></p>
</li>
<li><p><strong>Configure AWS CLI without manual input</strong></p>
</li>
<li><p><strong>Create an EC2 instance automatically</strong></p>
</li>
<li><p><strong>Ensure the instance reaches a running state</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740165193431/4302833f-7ea3-4442-82c5-3d687dc94cf7.png" alt class="image--center mx-auto" /></p>
<p>This project helped me understand how <strong>real-world automation works in DevOps</strong>.</p>
<h3 id="heading-resources-i-used-for-bash-scripting"><strong>Resources I Used for Bash Scripting:</strong></h3>
<ol>
<li><p><a target="_blank" href="https://youtube.com/playlist?list=PLT98CRl2KxKGj-VKtApD8-zCqSaN2mD4w&amp;si=q6vUCZIOYUy3gS2U">Learn Linux TV | Bash Scripting</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/9Xl1ZTk3BQw?si=hm5Iqc21ujCN8_Hg">Shell Scripting in One Shot | Train With Shubham</a></p>
</li>
</ol>
<hr />
<h2 id="heading-challenges-i-faced">Challenges I Faced</h2>
<p>1️⃣ <strong>Understanding Data Flow in Networking</strong></p>
<ul>
<li><p><strong>Problem:</strong> Couldn't grasp how <strong>data flows across layers in networking models</strong>.</p>
</li>
<li><p><strong>Solution:</strong> Asked my <strong>roommate (who studied CN)</strong>, and he explained it with real-world examples.</p>
</li>
</ul>
<p>2️⃣ <strong>Errors in Django Deployment</strong></p>
<ul>
<li><strong>Solution:</strong> Used <strong>Stack Overflow &amp; ChatGPT</strong> to debug errors, modifying file permissions &amp; user ownership.</li>
</ul>
<p>3️⃣ <strong>Automating AWS CLI Configuration</strong></p>
<ul>
<li><strong>Solution:</strong> Discovered where AWS stores credentials and wrote a script to automate the process.</li>
</ul>
<hr />
<h2 id="heading-whats-next">What’s Next?</h2>
<p>Next week, I plan to:<br />✅ <strong>Explore more Bash scripting projects</strong><br />✅ <strong>Learn Makefile for automation</strong><br />✅ <strong>Revise Python basics &amp; explore advanced Python for DevOps</strong></p>
<hr />
<h2 id="heading-lets-connect">Let’s Connect!</h2>
<p><strong>LinkedIn:</strong> <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/">My LinkedIn Profile</a> <strong>GitHub:</strong> <a target="_blank" href="https://github.com/Akshansh029">My GitHub Profile</a><br />If you have any <strong>recommended resources, better approaches to my challenges, or insights</strong>, I’d love to hear them! Drop your thoughts in the comments.</p>
<p><strong>Have a wonderful day!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Delving into Git, Networking & Open Source]]></title><description><![CDATA[Introduction
Hello there! 👋 Last week marked Week 2 of my DevOps journey. Due to my sports commitments, I had limited time, but I still managed to learn and explore several key topics. This week, I completed advanced Linux commands, Git + GitHub, Co...]]></description><link>https://blog.akshanshsingh.com/delving-into-git-networking-and-open-source</link><guid isPermaLink="true">https://blog.akshanshsingh.com/delving-into-git-networking-and-open-source</guid><category><![CDATA[Devops]]></category><category><![CDATA[learning]]></category><category><![CDATA[#learning-in-public]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[Git]]></category><category><![CDATA[computer networking]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Fri, 14 Feb 2025 16:42:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739551418061/9b4a5127-f320-4978-afe6-67dc6f514b4d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! 👋 Last week marked <strong>Week 2</strong> of my DevOps journey. Due to my sports commitments, I had limited time, but I still managed to learn and explore several key topics. This week, I completed <strong>advanced Linux commands, Git + GitHub, Computer Network fundamentals, and</strong> a bit about <strong>Open Source contributions</strong>. Though progress was a bit slow, learning something new always counts!</p>
<hr />
<h2 id="heading-wrapping-up-linux-advanced-commands">Wrapping Up Linux: Advanced Commands</h2>
<p>In my previous week, I covered <strong>basic Linux commands</strong>, but a few advanced commands were still left. I focused on <strong>find, grep, awk, and sed</strong>:</p>
<p><strong>➡️ grep</strong> - Used to search for a particular pattern in a file.<br /><strong>➡️ find</strong> → Searches for files and directories based on name, size, type, etc.<br /><strong>➡️ awk</strong> → A scripting language mainly used for text processing, filtering, and formatting structured data.<br /><strong>➡️ sed</strong> → A stream editor that works on character streams for pattern matching and replacements.</p>
<p>Now that I have a solid grasp of Linux basics, I plan to deepen my understanding by practising more with real-world assignments and tasks.</p>
<hr />
<h2 id="heading-deep-dive-into-git-and-github">Deep Dive into Git and GitHub</h2>
<p>As a web developer, I had experience using <strong>Git and GitHub</strong>, but for DevOps, I needed to <strong>expand my knowledge</strong>. I revised Git basics and moved to advanced topics like <strong>branches, pull requests, and resolving merge conflicts</strong>. Learning best practices for branch creation and conflict resolution helped me understand how teams collaborate efficiently in a DevOps environment.</p>
<p>While learning GitHub, I stumbled upon <strong>Open Source Contributions</strong> and decided to explore how Open Source projects work and how to contribute.</p>
<hr />
<h2 id="heading-getting-started-with-open-source-contributions">Getting Started with Open Source Contributions</h2>
<p>I watched several videos and read about <strong>how to contribute to Open Source projects</strong>. Here’s the step-by-step process I learned:</p>
<h3 id="heading-1-what-is-open-source"><strong>1. What is Open Source?</strong></h3>
<p>Open source refers to any program whose <strong>source code is publicly available</strong> for modification, contribution, and improvement.</p>
<h3 id="heading-2-finding-a-repository-to-contribute"><strong>2. Finding a Repository to Contribute</strong></h3>
<p>Use <strong>GitHub/GitLab search</strong> to find a project related to your preferred tech stack.</p>
<h3 id="heading-3-finding-the-right-issue"><strong>3. Finding the Right Issue</strong></h3>
<p>Start with <strong>"good first issues"</strong> in the <strong>issues</strong> tab of a repository. These are beginner-friendly and help you get started.</p>
<h3 id="heading-4-understand-and-validate-the-issue"><strong>4. Understand and Validate the Issue</strong></h3>
<p>Before contributing, ensure you understand the issue and check the discussion to validate its relevance.</p>
<h3 id="heading-5-fork-and-start-contributing"><strong>5. Fork and Start Contributing</strong></h3>
<p>Since you don’t have access to the original repository, <strong>fork (copy) the repo</strong> to your account and start working on your own copy.</p>
<h3 id="heading-6-create-relevant-branches"><strong>6. Create Relevant Branches</strong></h3>
<p>Never work in the <code>main</code> or <code>master</code> branch. Follow branch naming conventions:</p>
<ul>
<li><p><strong>Bug fixes</strong> → <code>fix/&lt;bug_name&gt;</code></p>
</li>
<li><p><strong>New Features</strong> → <code>feat/&lt;feature_name&gt;</code></p>
</li>
</ul>
<h3 id="heading-7-test-before-creating-a-pull-request-pr"><strong>7. Test Before Creating a Pull Request (PR)</strong></h3>
<p>Before submitting a PR, ensure the changes work correctly and pass all required tests.</p>
<h3 id="heading-8-link-pr-to-issue"><strong>8. Link PR to Issue</strong></h3>
<p>Mention the issue number in your PR description:</p>
<ul>
<li><p><code>fixes: #issue_number</code></p>
</li>
<li><p><code>resolves: #issue_number</code></p>
</li>
</ul>
<h3 id="heading-9-wait-for-the-maintainers-review"><strong>9. Wait for the Maintainer’s Review</strong></h3>
<p>Be patient while the <strong>project maintainer reviews your PR</strong>. Engage in discussions if needed.</p>
<h3 id="heading-10-repeat"><strong>10. Repeat</strong></h3>
<p>Find another issue and continue contributing!</p>
<p>This was the step-by-step guide provided in the YouTube video.<br />I plan to find a suitable repository and make my first <strong>Open Source contribution</strong> in the coming days.</p>
<h3 id="heading-resources-i-used"><strong>Resources I Used:</strong></h3>
<ul>
<li><p><strong>Git/GitHub</strong> → <a target="_blank" href="https://youtu.be/apGV9Kg7ics?si=-FogOt505gmAY8lu">Kunal Kushwaha - Complete Git and GitHub Tutorial</a></p>
</li>
<li><p><strong>Open Source Contributions</strong> → <a target="_blank" href="https://youtube.com/playlist?list=PLinedj3B30sAT6CotNj0iffhRV89SkNK9&amp;si=upDIkUq2ysgDn431">Piyush Garg (Open Source Bootcamp)</a></p>
</li>
</ul>
<hr />
<h2 id="heading-learning-computer-networking-fundamentals">Learning Computer Networking Fundamentals</h2>
<p>After exploring Open Source, I returned to my roadmap and focused on <strong>Computer Networking</strong>. I started with:</p>
<h3 id="heading-1-history-of-the-internet"><strong>1. History of the Internet</strong></h3>
<p>Understanding why and how the internet was created helped me appreciate its evolution and role in modern computing.</p>
<h3 id="heading-2-network-protocols"><strong>2. Network Protocols</strong></h3>
<p>I explored different <strong>protocols</strong>, including <strong>HTTP</strong>, its methods, and status codes.</p>
<h3 id="heading-3-network-architectures"><strong>3. Network Architectures</strong></h3>
<p>I studied two primary architectures:</p>
<ul>
<li><p><strong>Client-Server Architecture</strong></p>
</li>
<li><p><strong>Peer-to-Peer Architecture</strong></p>
</li>
</ul>
<h3 id="heading-4-network-topologies-amp-types"><strong>4. Network Topologies &amp; Types</strong></h3>
<p>I learned about <strong>LAN, MAN, WAN</strong> and different <strong>network topologies</strong> used in enterprise environments.</p>
<h3 id="heading-5-osi-model"><strong>5. OSI Model</strong></h3>
<p>One of the major topics I explored was the <strong>OSI (Open Systems Interconnection) Model</strong>, which consists of <strong>7 layers</strong>:</p>
<ul>
<li><p><strong>Application Layer</strong></p>
</li>
<li><p><strong>Presentation Layer</strong></p>
</li>
<li><p><strong>Session Layer</strong></p>
</li>
<li><p><strong>Transport Layer</strong></p>
</li>
<li><p><strong>Network Layer</strong></p>
</li>
<li><p><strong>Data Link Layer</strong></p>
</li>
<li><p><strong>Physical Layer</strong></p>
<p>  <img src="https://media.geeksforgeeks.org/wp-content/uploads/20250117112545142665/OSI-Model-.webp" alt="OSI-Model-.webp" /></p>
</li>
</ul>
<p>Each layer has specific responsibilities and protocols that ensure <strong>seamless data transfer</strong> over networks. I also studied how <strong>emails work</strong> and the different protocols used in email communication.</p>
<h3 id="heading-resources-i-used-1"><strong>Resources I Used:</strong></h3>
<ul>
<li><p><strong>Computer Networking</strong> → <a target="_blank" href="https://youtu.be/IPvYjXCsTg8?si=BrlnaM1NlGn-_MNr">Kunal Kushwaha - Computer Networking Full Course</a></p>
</li>
<li><p><strong>GeeksforGeeks Networking Articles</strong></p>
</li>
</ul>
<hr />
<h2 id="heading-challenges-i-faced-amp-how-i-overcame-them">Challenges I Faced &amp; How I Overcame Them</h2>
<ol>
<li><p><strong>Understanding Differences Between</strong> <code>grep</code>, <code>awk</code>, and <code>sed</code></p>
<p> <strong>🔹 Problem:</strong> I was confused about when to use each command.</p>
<p> <strong>🔹 Solution:</strong> I searched for real-world examples and experimented with them.</p>
<p> <strong>🔹 Resources:</strong> <a target="_blank" href="https://www.baeldung.com/linux/grep-sed-awk-differences">Baeldung - grep, sed, awk differences</a>, <a target="_blank" href="https://www.linode.com/docs/guides/differences-between-grep-sed-awk/">Linode - awk, grep, sed differences</a></p>
</li>
<li><p><strong>Getting Started with Open Source Contributions</strong></p>
<p> <strong>🔹 Problem:</strong> I can't determine a starting point for Open Source Contribution.</p>
</li>
</ol>
<hr />
<h2 id="heading-whats-next">What’s Next?</h2>
<p>For next week, my goals are:<br />✅ <strong>Understanding how DNS works</strong><br />✅ <strong>Deep dive into each OSI model layer</strong><br />✅ <strong>Getting started with Bash Scripting</strong></p>
<hr />
<h2 id="heading-lets-connect">Let’s Connect!</h2>
<p>If you have any recommended resources, some better approaches to challenges I faced, insights, or tips, I’d love to hear from you! Drop them in the comments. <strong>Thank you for reading till the end!</strong></p>
<p><strong>Have a wonderful day.</strong></p>
]]></content:encoded></item><item><title><![CDATA[First Steps into DevOps and Linux]]></title><description><![CDATA[Introduction
Hello there! 👋 Last Sunday, I officially began my DevOps journey, and this past week has been an exciting deep dive into its fundamentals. I started by understanding what DevOps is, its ideology, core concepts, and terminologies. Alongs...]]></description><link>https://blog.akshanshsingh.com/first-steps-into-devops-and-linux</link><guid isPermaLink="true">https://blog.akshanshsingh.com/first-steps-into-devops-and-linux</guid><category><![CDATA[Devops]]></category><category><![CDATA[#LearninPublic]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Fri, 07 Feb 2025 20:00:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738958318393/405a282b-fa5f-4866-8626-4c5a5d77e594.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there! 👋 Last Sunday, I officially began my DevOps journey, and this past week has been an exciting deep dive into its fundamentals. I started by understanding what DevOps is, its ideology, core concepts, and terminologies. Alongside this, I ventured into the world of Linux—exploring installation methods, different Linux distributions, and, most importantly, learning essential commands. In this blog, I'll share my learnings, challenges, and how I overcame them.</p>
<h2 id="heading-understanding-devops-beyond-just-a-definition">Understanding DevOps: Beyond Just a Definition</h2>
<p>When I first asked myself, <strong>"What is DevOps?"</strong>, the common definition I found was:</p>
<blockquote>
<p>DevOps is a set of practices that integrates software development (Dev) and IT operations (Ops) to shorten the development lifecycle while maintaining high software quality.</p>
</blockquote>
<p>However, I quickly realized that DevOps is much more than a set of practices; it is a <strong>philosophy</strong>. It encourages collaboration between development and operations teams, reducing friction and accelerating code deployment into production.</p>
<h3 id="heading-the-software-development-lifecycle-sdlc"><strong>The Software Development Lifecycle (SDLC)</strong></h3>
<p>I also came across the <strong>Software Development Life Cycle (SDLC)</strong>, a structured process to develop software efficiently. It consists of:</p>
<ul>
<li><p><strong>Planning</strong> → Identifying requirements and setting goals.</p>
</li>
<li><p><strong>Design</strong> → Creating architecture and technical specifications.</p>
</li>
<li><p><strong>Development</strong> → Writing the actual code.</p>
</li>
<li><p><strong>Testing</strong> → Ensuring the software works as expected.</p>
</li>
<li><p><strong>Deployment</strong> → Releasing the software into production.</p>
</li>
<li><p><strong>Operate &amp; Monitor</strong> → Maintaining performance and addressing issues.</p>
</li>
</ul>
<p><img src="https://media.geeksforgeeks.org/wp-content/uploads/20230412162703/DevOps-lifecycle.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-continuous-integration-amp-continuous-deployment-cicd"><strong>Continuous Integration &amp; Continuous Deployment (CI/CD)</strong></h3>
<p>One of the most fascinating concepts I encountered was <strong>CI/CD</strong>:</p>
<p><strong>➡️ Continuous Integration (CI)</strong> ensures that developers frequently merge their code into a shared repository, where it is automatically tested and built.</p>
<p><strong>➡️ Continuous Deployment (CD)</strong> automates the process of releasing tested code, deploying it to production, and monitoring it for issues.</p>
<p>The main goal of CI/CD is to <strong>reduce human intervention, speed up deployment, and enhance code quality</strong>, thus minimizing the risk of large-scale failures.</p>
<h3 id="heading-deployment-strategies"><strong>Deployment Strategies</strong></h3>
<p>I also learned about different strategies used in production environments:</p>
<p><strong>➡️ Rolling Deployment</strong>: Gradually replacing the old version of an application with a new one.</p>
<p><strong>➡️ Blue/Green Deployment</strong>: Running two identical environments—one (blue) with the existing version and another (green) with the new version. Traffic is switched once testing is successful.</p>
<p>Other important concepts I explored include <strong>Virtual Machines (VMs), Containers, Linters, Log Aggregation, and Production Metrics.</strong></p>
<h3 id="heading-resources-i-used-for-devops-basics"><strong>Resources I Used for DevOps Basics:</strong></h3>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=0yWAtQ6wYNM">TechWorld with Nana: What is DevOps? REALLY Understand It | DevOps vs SRE</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=j5Zsa_eOXeY">freeCodeCamp.org: DevOps Engineering Course for Beginners</a></p>
</li>
<li><p><a target="_blank" href="https://www.geeksforgeeks.org/introduction-to-devops/">GeeksforGeeks: What is DevOps?</a></p>
</li>
</ul>
<p>After two days of DevOps basics, I moved on to <strong>Linux</strong>, and honestly, I was a bit nervous to start. But here’s how it went😅.</p>
<h2 id="heading-getting-started-with-linux">Getting Started with Linux</h2>
<p>To begin my Linux journey, I first understood what Linux is:</p>
<blockquote>
<p>Linux is an open-source operating system widely used for servers, development, and personal computing due to its security, flexibility, and stability.</p>
</blockquote>
<p>I came across essential Linux components:</p>
<p>➡️ <strong>Kernel</strong>: The core of the OS, managing hardware-software interactions.</p>
<p>➡️ <strong>Bootloader</strong>: Loads the operating system into memory when the computer starts.</p>
<p>➡️ <strong>Shell</strong>: An interface to interact with the OS via commands.</p>
<p><img src="https://images.javatpoint.com/linux/images/architecture-of-linux.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-running-linux-on-my-windows-system"><strong>Running Linux on My Windows System</strong></h3>
<p>Among various methods, I chose <strong>Virtual Machines (VMs)</strong>. I installed <strong>VirtualBox</strong> and configured a Linux server. Later, I explored <strong>Vagrant</strong>, which <strong>automates VM creation</strong> and makes setup much easier.</p>
<h3 id="heading-essential-linux-commands-i-learned"><strong>Essential Linux Commands I Learned</strong></h3>
<p>I started with <strong>basic navigational commands</strong>:</p>
<p>➡️ <code>pwd</code>, <code>ls</code>, <code>cd</code> – for navigating the file system.</p>
<p>➡️ File management commands: <code>touch</code>, <code>echo</code>, <code>cat</code>, <code>cp</code>, <code>mv</code>, <code>rm</code>, <code>ls</code>.</p>
<p>➡️ System commands: <code>df</code>, <code>du</code>, <code>top</code>, <code>ps</code>, <code>fuser</code>, <code>vmstat</code>.</p>
<p>➡️ <strong>The fascinating</strong> <code>nohup</code> command—used to run processes even after system shutdown and store process logs.</p>
<p>Next, I explored <strong>User &amp; Group Management:</strong></p>
<p>➡️ Creating, deleting, switching users (<code>useradd</code>, <code>userdel</code>, <code>su</code>).</p>
<p>➡️ Managing groups (<code>groupadd</code>, <code>groupdel</code>, <code>usermod</code>).</p>
<p>➡️ File permissions using <code>chmod</code> and <strong>the importance of ****</strong><code>sudo</code>.</p>
<p>I also tackled <strong>Network Commands</strong>, including <code>ping</code>, <code>netstat</code>, <code>ip</code>, <code>traceroute</code>, <code>mtr</code>, <code>dig</code>, <code>curl</code>, and <code>wget</code>. These were confusing at first, but practice made them clearer.</p>
<p><img src="https://media.geeksforgeeks.org/wp-content/uploads/20230516105759/151.webp" alt="Linux file system" class="image--center mx-auto" /></p>
<h3 id="heading-resources-i-used-for-linux"><strong>Resources I Used for Linux:</strong></h3>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=e01GGTKmtpc">TrainWithShubham: Linux For DevOps In One Shot | Beginners to Advanced</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=iwolPf6kN-k">Kunal Kushwaha: Introduction to Linux &amp; Terminal Commands - Full Course</a></p>
</li>
</ul>
<h2 id="heading-challenges-i-faced-amp-solutions">Challenges I Faced &amp; Solutions</h2>
<ol>
<li><strong>File Permission Issue in Vagrant</strong></li>
</ol>
<p>🔹 <strong>Problem:</strong> Initially, I couldn’t change file permissions inside the <code>/vagrant</code> directory. I learned that Vagrant uses VirtualBox's default settings, which override permission changes.</p>
<p>🔹 <strong>Solution:</strong> <code>/vagrant</code> is a <strong>shared folder between the host and VM</strong>, so permission changes were overridden. I either had to modify <code>Vagrantfile</code> settings or work in <code>/home/vagrant</code>, which resolved the issue.</p>
<ol start="2">
<li><strong>Struggles with User &amp; Group Management Commands</strong></li>
</ol>
<p>🔹 <strong>Problem:</strong> While I could handle basic file operations, user management commands were tricky.</p>
<p>🔹 <strong>Solution:</strong> I practised more <strong>real-world examples</strong> and used <strong>ChatGPT</strong> for additional scenarios to get a deeper understanding.</p>
<ol start="3">
<li><strong>Network Commands Were Overwhelming</strong></li>
</ol>
<p>🔹 <strong>Problem:</strong> Too many commands at once felt confusing, and many seemed to have similar outputs.</p>
<p>🔹 <strong>Solution:</strong> I took a break, revised, and executed each command sequentially to observe differences. Practice is key!</p>
<h2 id="heading-whats-next">What’s Next?</h2>
<p>This past week has been exciting, challenging, and deeply rewarding. For the next week, I plan to:</p>
<p>✅ Complete advanced Linux commands (grep, awk, etc.)<br />✅ Dive deeper into <strong>Git and GitHub</strong><br />✅ Begin learning <strong>Networking Fundamentals</strong></p>
<p>I know the basics of Git and GitHub, but this time, I aim to go in-depth and explore real-world workflows.</p>
<h3 id="heading-lets-connect"><strong>Let’s Connect!</strong></h3>
<p>If you have any <strong>recommended resources, insights, or tips</strong>, I’d love to hear from you! Drop them in the comments. Thank you for staying with me till the last.</p>
<hr />
<p><strong>Have a wonderful day.</strong></p>
]]></content:encoded></item><item><title><![CDATA[My DevOps Adventure Starts]]></title><description><![CDATA[Introduction
Hello there!👋 My name is Akshansh Singh, and I am a pre-final year engineering student at VIT Chennai. Over the past 2.5 to 3 years, I have been deeply involved in web development, building projects that not only enhanced my skills but ...]]></description><link>https://blog.akshanshsingh.com/my-devops-adventure-starts</link><guid isPermaLink="true">https://blog.akshanshsingh.com/my-devops-adventure-starts</guid><category><![CDATA[Learning Journey]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Akshansh Singh]]></dc:creator><pubDate>Sun, 02 Feb 2025 06:45:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/f7uCQxhucw4/upload/aa2ca928adc49fb8038d1ac166f5165c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello there!👋 My name is Akshansh Singh, and I am a pre-final year engineering student at VIT Chennai. Over the past 2.5 to 3 years, I have been deeply involved in web development, building projects that not only enhanced my skills but also made the learning process enjoyable. Apart from web development, I have always been curious about new technologies and trends in the tech world, keeping myself updated through various articles and blogs. It was through web development that I first encountered the concept of deploying applications, which eventually led me to explore the vast domain of DevOps.</p>
<h2 id="heading-how-i-discovered-devops">How I Discovered DevOps</h2>
<p>Initially, I deployed my projects using platforms like Vercel, Netlify, and Render. While these platforms made deployment relatively easy, I faced a major challenge when deploying one of my projects, <code>CodeChime</code>—a WebSocket-based code editor. Everything worked perfectly in my local development environment, but as soon as I moved to production, things started breaking. It took me almost two to three days to identify and fix the issue. That was when I started wondering how large enterprises manage to deploy complex applications at scale without facing such problems.</p>
<p>To satisfy my curiosity, I began reading about how modern applications are built, tested, released, and deployed efficiently. That was my first real introduction to DevOps. As I delved deeper, I realized that DevOps is not just about deployment—it is an entire ecosystem of processes and tools designed to streamline software development and operations. I read more about its importance in the tech industry, the career opportunities it offers, and the skill set required to become a DevOps engineer. The more I explored, the more I became fascinated by the field.</p>
<h2 id="heading-my-approach-to-learning-devops">My Approach to Learning DevOps</h2>
<p>Once I decided to take DevOps seriously, my initial thought was to follow a structured course. I spent three to four days searching for online courses but was disappointed to find that free courses lacked depth, while the paid ones were too expensive. That’s when I decided to take a different approach—designing my own roadmap for learning DevOps.</p>
<p>Having previously followed <a target="_blank" href="https://roadmap.sh/">roadmap.sh</a> for web development, I turned to their DevOps roadmap. It gave me a broad overview of the necessary concepts and tools, helping me identify where to start. To supplement my learning, I spent an entire day watching YouTube videos and came across insightful content from <a class="user-mention" href="https://hashnode.com/@kunalk">Kunal Kushwaha</a> and <a class="user-mention" href="https://hashnode.com/@savinderpuri">savinder puri</a>. Their videos introduced me to the idea of <strong>learning in public</strong>—sharing my progress, experiences, and knowledge with others through blogging. This concept resonated with me, and I saw it as an excellent opportunity to document my journey while engaging with the DevOps community. ✨</p>
<h2 id="heading-why-learn-in-public">Why Learn in Public?</h2>
<p>The idea of learning in public appealed to me for several reasons:</p>
<p>✅ It helps reinforce my understanding of concepts by articulating them in my own words.</p>
<p>✅ It provides an opportunity to receive feedback from experienced professionals who can guide me in the right direction.</p>
<p>✅ It allows me to contribute to the DevOps community by sharing insights that might help other beginners like me.</p>
<p>Inspired by what I learned, I decided to start blogging on <strong>Hashnode</strong> as a way to track my progress and engage with the DevOps community.</p>
<h2 id="heading-my-devops-learning-plan">My DevOps Learning Plan</h2>
<p>To ensure a structured and practical approach to learning DevOps, I have outlined a plan that includes both theoretical understanding and hands-on practice. Here’s what I intend to do:</p>
<p>➡️ <strong>Understanding DevOps Fundamentals</strong> – Before diving into tools, I want to grasp the ideology behind DevOps. What problems does it solve? How does it improve the development lifecycle? What does a DevOps engineer do in real-world scenarios?</p>
<p>➡️ <strong>Learning Linux and Shell Scripting</strong> – Since Linux is the foundation of many DevOps tools, I will start with its basics, including important commands, file handling, process management, and shell scripting.</p>
<p>➡️ <strong>Version Control with Git</strong> – While I am already familiar with Git from web development, I will explore advanced workflows, branching strategies, and collaboration techniques.</p>
<p>➡️ <strong>Networking Fundamentals</strong> – Understanding the basics of networking, including protocols, DNS, load balancing, and security aspects.</p>
<p>➡️ <strong>Cloud Services Fundamentals</strong> – Learning the core services of AWS, including EC2, S3, IAM, and VPC to understand cloud infrastructure.</p>
<p>➡️ <strong>Containerization with Docker</strong> – Containers play a significant role in DevOps. Learning Docker will help me understand how to package applications efficiently.</p>
<p>➡️ <strong>CI/CD Pipelines</strong> – Setting up Continuous Integration and Continuous Deployment pipelines using tools like Jenkins, GitHub Actions, or GitLab CI/CD.</p>
<p>➡️ <strong>Infrastructure as Code (IaC)</strong> – Learning about Terraform and Ansible to automate infrastructure deployment and management.</p>
<p>➡️ <strong>Monitoring and Logging</strong> – Exploring tools like Prometheus, Grafana, and ELK stack to ensure system reliability and performance monitoring.</p>
<p>This roadmap will serve as my guide, but I also expect to adapt and refine it based on my experiences along the way.</p>
<h2 id="heading-what-to-expect-from-my-blog">What to Expect from My Blog</h2>
<p>Starting today, I will be sharing my weekly learnings and experiences on Hashnode. My blogs will cover:</p>
<ul>
<li><p><strong>What I learned</strong> – Concepts, tools, and best practices.</p>
</li>
<li><p><strong>Why I learned it</strong> – The importance of each topic in the DevOps workflow.</p>
</li>
<li><p><strong>How I learned it</strong> – Resources, challenges faced, and practical applications.</p>
</li>
</ul>
<p>I also plan to work on small projects to solidify my understanding and validate my learning. These projects will help me implement DevOps principles in real-world scenarios and build a strong portfolio.</p>
<h2 id="heading-join-me-on-this-journey">Join Me on This Journey</h2>
<p>I believe this will be an exciting and rewarding journey, and I welcome anyone interested in DevOps to follow along. Whether you’re an experienced professional, a beginner like me, or someone curious about DevOps, your insights, feedback, and suggestions will be highly valuable.</p>
<p>Feel free to connect with me on <a target="_blank" href="https://www.linkedin.com/in/akshansh-singh-3b6718250/"><strong>LinkedIn</strong></a> or check out my <a target="_blank" href="https://github.com/Akshansh029"><strong>GitHub</strong></a> profile. If you have any recommended resources, tips, or experiences to share, I would love to hear from you in the comments. 💡</p>
<hr />
<p><strong>Have a wonderful day.</strong></p>
]]></content:encoded></item></channel></rss>