<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aisalkyn Aidarova</title>
    <description>The latest articles on DEV Community by Aisalkyn Aidarova (@jumptotech).</description>
    <link>https://dev.to/jumptotech</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3549986%2F7a403ca9-0459-412a-b618-71699480d58d.png</url>
      <title>DEV Community: Aisalkyn Aidarova</title>
      <link>https://dev.to/jumptotech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jumptotech"/>
    <language>en</language>
    <item>
      <title>Tell me about yourself.</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Fri, 06 Nov 2026 20:11:57 +0000</pubDate>
      <link>https://dev.to/jumptotech/tell-me-about-yourself-1j4</link>
      <guid>https://dev.to/jumptotech/tell-me-about-yourself-1j4</guid>
      <description>&lt;p&gt;Tell me about yourself.&lt;br&gt;
I am DevOps Engineer with more than 5 years experience. I started at Southwest Airlines as Cloud Engineer, and after one year I got promoted to DevOps Engineer. Since September 2023 I work at Capital One. Mostly I work with AWS, Kubernetes, Terraform and GitLab CI/CD. I also used Azure, and monitoring tools like Prometheus, Grafana and Datadog. I support production, do on-call, and work on reliability, security and cost. I like to automate manual work and help developers ship apps safely.&lt;br&gt;
Why BigTime?&lt;br&gt;
You are building AI-powered platform, and I think AI brings many good opportunities for DevOps. Your stack is AWS, Kubernetes, Terraform and GitLab, and this is what I work with every day. I also like that engineers get ownership and solve problems independently.&lt;br&gt;
What is your day to day?&lt;br&gt;
In the morning I check alerts and dashboards in Datadog and Grafana. Then standup. Most of the day I work on Terraform, GitLab pipelines and deployments to EKS with Helm. I help developers when deployments fail. I do patching, upgrades, cost and security work. When I am on-call, I handle incidents. I update documentation in Confluence.&lt;br&gt;
Tell me about a hard production incident.&lt;br&gt;
After a release we had 60 replicas in 3 Availability Zones, and HTTP 500 errors went up to 18 percent. I was the on-call engineer. I checked dashboards, logs, Kubernetes deployment status and the deployment history. The errors started with the release, so we rolled back to the last stable version. I checked that pods were healthy and the error rate went down. Root cause was wrong database connection setting in the new version. After this I added canary deployments, smoke tests in the pipeline, automatic rollback on high error rate, and wrote a postmortem and runbook.&lt;br&gt;
How do you replace long-lived credentials?&lt;br&gt;
I move secrets to Vault or AWS Secrets Manager with automatic rotation. Apps on EKS use IAM roles for service accounts, so pods get short-lived credentials. GitLab pipelines use OIDC to assume IAM roles, no static AWS keys. EC2 and Windows servers use instance roles. For RDS, passwords are in Secrets Manager with rotation. This helps with SOC 2 audits too.&lt;br&gt;
Windows EC2 in production, you cannot RDP, and you cannot restart. What do you do?&lt;br&gt;
First I check if the app still works for users, maybe only RDP is broken. I check status checks, security group port 3389, NACL, route table, and the Route 53 record. Then I use SSM Session Manager or Run Command with PowerShell. I check if the RDP service is running and restart only this service, check Windows firewall, CPU, memory and disk space. I look at the console screenshot, system log and CloudWatch metrics. If restart is really needed, I take a snapshot, move traffic to other instances behind the load balancer, talk to the team, and do it in a maintenance window.&lt;br&gt;
How did you save $160K?&lt;br&gt;
I added cost allocation tags so we see who spends what. I rightsized big EC2 instances, turned off dev and test at night and weekends, cleaned unused EBS volumes, snapshots and load balancers. S3 lifecycle policies to cheaper storage. Better EKS node sizing and autoscaling. Savings Plans and Reserved Instances for stable workloads. Budgets and alerts in Cost Explorer and CloudWatch.&lt;br&gt;
How did you reduce MTTD by 25 percent?&lt;br&gt;
I made better dashboards in Grafana and Datadog for each service. Alerts based on real symptoms like error rate, latency and pod restarts. I removed noisy alerts so the team trusts them. I added health checks and synthetic monitoring. Alerts go to PagerDuty and Slack with runbook links.&lt;br&gt;
Biggest issue you fixed with Grafana?&lt;br&gt;
Booking service on EKS was slow every few days. I made a dashboard with memory, restarts and latency together. Memory went up slowly, then pods got OOMKilled and latency jumped. It was a memory leak and low memory limits. Developers fixed the leak, I fixed requests and limits and added alerts for memory growth and restarts.&lt;br&gt;
What are the RDS replication types?&lt;br&gt;
Multi-AZ is synchronous replication to a standby in another Availability Zone, for high availability and automatic failover, you cannot read from it. Read Replicas are asynchronous, for scaling reads and reporting, can be cross-region, and can be promoted for disaster recovery. SQL Server Multi-AZ uses Always On or mirroring.&lt;br&gt;
RDS vs Aurora?&lt;br&gt;
Standard RDS is managed database with its own EBS storage per instance. Aurora is AWS cloud database for MySQL and PostgreSQL. Storage is shared and separate from compute, data copied 6 times across 3 Availability Zones, storage grows automatically. Up to 15 replicas with very low lag, failover under 30 seconds. Aurora is faster but more expensive. Aurora does not support SQL Server.&lt;br&gt;
GitLab pipeline with two different AWS roles, how do you configure?&lt;br&gt;
I use GitLab OIDC. The job gets an ID token and assumes IAM role. Role one is read-only for terraform plan, runs on merge requests. Role two has write permissions for apply and deploy, and the trust policy allows only main branch, protected branch and production environment. Stages are validate, plan, apply, deploy. Apply is manual approval with the saved plan. Deploy updates kubeconfig and runs helm upgrade. In EKS I map the role to RBAC with access entries, so it deploys only to its namespaces.&lt;br&gt;
What happens when you type bigtime.net in browser?&lt;br&gt;
DNS finds the IP with UDP port 53, through the resolver to Route 53. Then TCP three-way handshake, SYN, SYN-ACK, ACK. Then TLS handshake on port 443, server sends certificate and they agree on keys. Then HTTP GET request. Traffic goes through CloudFront or load balancer, then to EC2 or EKS, and the app talks to RDS. Response comes back and browser shows the page.&lt;br&gt;
How do you make sure the app uses S3 securely, encryption in transit?&lt;br&gt;
Bucket policy denies requests when aws:SecureTransport is false, so only HTTPS. I can require TLS 1.2 with s3:TlsVersion. App uses IAM role, least privilege, no keys. VPC gateway endpoint so traffic stays private, and bucket policy limited to this endpoint. Block Public Access on. Check with CloudTrail and AWS Config rule s3-bucket-ssl-requests-only.&lt;br&gt;
Some S3 objects are not encrypted with your KMS key, why and how to fix?&lt;br&gt;
Default encryption works only for new objects, so old objects keep old encryption. Also if the client sends its own encryption header, it overrides the default. I find them with S3 Inventory. I re-encrypt with S3 Batch Operations copy in place. To prevent, bucket policy denies PutObject if encryption is not aws:kms or the key ID is not my key ARN. KMS key policy allows only the right roles. AWS Config for monitoring.&lt;br&gt;
Same Terraform module in dev and prod, you add an IP range, dev plan is clean, prod plan wants to destroy route table associations. Why?&lt;br&gt;
The module uses count with a list. Terraform tracks resources by index. In prod the list is longer or in different order, so new item shifts indexes and Terraform wants to destroy and recreate. Fix is for_each with stable keys like the IP range. Use moved blocks or terraform state mv to move existing resources without destroy. Add prevent_destroy on critical resources, and require approval in the pipeline if prod plan shows destroy. Also check drift with plan -refresh-only and provider versions.&lt;br&gt;
Kubernetes app gets 502 for about 10 seconds during every deployment. Readiness probe is present. What do you check?&lt;br&gt;
Most likely old pods shutting down. Kubernetes sends SIGTERM and removes the pod at the same time, but the load balancer still sends traffic for few seconds. Fix is preStop hook with sleep 10 to 15 seconds, app handles SIGTERM gracefully, terminationGracePeriodSeconds longer than the sleep. Rolling update with maxUnavailable 0 and maxSurge 1. With ALB, enable pod readiness gates and check deregistration delay and keep-alive timeout. Add PodDisruptionBudget. Check ALB logs and pod events.&lt;br&gt;
How do you use AI in your work?&lt;br&gt;
I use chat for quick questions and errors. For bigger tasks I use AI agents like Claude Code. It reads the repo, makes a plan, changes Terraform or pipelines, and runs terraform plan or tests. I review the plan and the changes before merge. Agents use tools through MCP and need limited permissions, like read-only in prod and no apply without human approval. I never put secrets or customer data into AI tools.&lt;/p&gt;

&lt;p&gt;Next round they may also ask these, because they are in the job description:&lt;/p&gt;

&lt;p&gt;How do you deploy and monitor .NET apps?&lt;br&gt;
I build the app in GitLab CI with dotnet build and dotnet test, then package it. For Windows on EC2, I deploy with PowerShell scripts or SSM Run Command to IIS, and take the server out of the load balancer during deploy. For Linux, I put .NET Core in Docker and deploy to EKS or ECS with Helm. For monitoring I use CloudWatch agent for Windows logs and IIS logs, and Datadog APM or OpenTelemetry for traces, errors and response time.&lt;br&gt;
How do you patch Windows and Linux servers?&lt;br&gt;
I use AWS Systems Manager Patch Manager with patch baselines and maintenance windows. First patch dev and test, then prod. For prod, I patch in groups, so not all servers behind the load balancer go down at once. Before patching I take snapshots. After patching I check the app health and the compliance report in SSM. For EKS nodes I update the AMI and do rolling node replacement.&lt;br&gt;
EKS vs ECS vs App Runner?&lt;br&gt;
EKS is Kubernetes, more control and flexible, good for complex apps, but more work to manage. ECS is AWS own container service, simpler, works well with Fargate and other AWS services. App Runner is the simplest, you give it image or code, and AWS handles everything, good for small web apps and APIs.&lt;br&gt;
What is Helmfile?&lt;br&gt;
Helmfile manages many Helm releases in one file. You define all charts, versions and values for each environment in one place, and run helmfile apply. It is good for keeping environments consistent and works well in CI/CD.&lt;br&gt;
What is Terragrunt and why use it?&lt;br&gt;
Terragrunt is a wrapper for Terraform. It keeps the code DRY, so you don’t copy the same backend and provider config in every environment. It manages remote state config, dependencies between modules, and lets you run plan or apply across many modules and accounts.&lt;br&gt;
How do you help with SOC 2?&lt;br&gt;
I make sure access is least privilege with IAM roles and SSO, encryption at rest with KMS and in transit with TLS, logs in CloudTrail and CloudWatch, vulnerability scanning with Inspector or image scanning in the pipeline, and patching. I keep evidence and documentation ready for auditors, like access reviews and change history from GitLab merge requests.&lt;br&gt;
What is your disaster recovery approach?&lt;br&gt;
First we agree on RTO and RPO with the business. Backups for RDS with automated snapshots and cross-region copies, S3 versioning and replication, all infrastructure in Terraform so we can rebuild fast. We write a DR runbook and test it, because a plan that is not tested does not work.&lt;br&gt;
Have you worked with Lambda?&lt;br&gt;
Yes, I used Lambda for automation, like stopping dev instances at night, cleaning old snapshots, and processing S3 events. I deploy it with Terraform, give it a small IAM role, and monitor with CloudWatch logs and alarms for errors and duration.&lt;br&gt;
What is Ansible used for?&lt;br&gt;
Configuration management. It connects to servers over SSH for Linux or WinRM for Windows, and runs playbooks to install software, change config and patch. It is agentless and idempotent, so you can run it many times and it gives the same result.&lt;br&gt;
Biggest weakness?&lt;br&gt;
Sometimes I go too deep into a problem and want to fix it myself. Now I set a time limit, and if I don’t solve it, I ask the team early.&lt;br&gt;
Where do you see yourself in 3 to 5 years?&lt;br&gt;
I want to grow into Senior or Lead DevOps Engineer, own bigger parts of the platform, and help build automation and AI tools for the team.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>career</category>
      <category>devops</category>
      <category>terraform</category>
    </item>
    <item>
      <title>HERC RENTALS INTERVIEW PREP Cloud and Platform Engineering Manager WHAT WE LEARNED IN ROUND ONE</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Fri, 06 Nov 2026 20:09:53 +0000</pubDate>
      <link>https://dev.to/jumptotech/herc-rentals-interview-prepcloud-and-platform-engineering-managerwhat-we-learned-in-round-one-3jc3</link>
      <guid>https://dev.to/jumptotech/herc-rentals-interview-prepcloud-and-platform-engineering-managerwhat-we-learned-in-round-one-3jc3</guid>
      <description>&lt;p&gt;HERC RENTALS INTERVIEW PREP&lt;br&gt;
Cloud and Platform Engineering Manager&lt;/p&gt;

&lt;p&gt;WHAT WE LEARNED IN ROUND ONE&lt;/p&gt;

&lt;p&gt;Team is 5 engineers, all senior and technically strong.&lt;br&gt;
Main problem is no clear structure or daily plan, people work in different directions.&lt;br&gt;
App teams do not fully understand the pipelines and need a simple standard path.&lt;br&gt;
Architecture and infra decisions are made together as a team, but there is no formal process.&lt;br&gt;
They use EKS for many microservices and ECS Fargate for small apps.&lt;br&gt;
Identity is Okta.&lt;br&gt;
AI is still at concept stage, integrating into backend apps, user access is limited, and they are careful because people misuse it.&lt;br&gt;
The manager wants someone who observes the current process first, finds gaps day to day, works close with another manager, and removes leadership blockers.&lt;br&gt;
Job post clouds are AWS, Azure, OCI with Terraform, CloudFormation and Bicep.&lt;br&gt;
Job is on-site in Bonita Springs, Florida.&lt;/p&gt;

&lt;p&gt;YOUR PITCH, TELL ME ABOUT YOURSELF&lt;/p&gt;

&lt;p&gt;Thank you for having me again. I am a DevOps engineer with more than five years of experience on AWS. Four years at Yelp and now at Zulily. My daily work is Terraform, Kubernetes on EKS, GitHub Actions pipelines and CloudWatch monitoring. At Yelp I improved deployment speed by 35 percent with blue-green deployments and automatic rollback. I also mentored junior engineers, wrote runbooks and helped onboard new people, and that is the part I enjoy most. In our first conversation I learned your team is very senior but needs structure and a clear path for app teams. That is exactly what I like to build. I want to stay hands-on and also help the team move in one direction.&lt;/p&gt;

&lt;p&gt;Numbers to remember: 5 plus years, 35 percent faster deployments, CKAD January 2025, AWS Solutions Architect Associate August 2026.&lt;/p&gt;

&lt;p&gt;LEADERSHIP ANSWERS&lt;/p&gt;

&lt;p&gt;What is your leadership experience?&lt;br&gt;
I have not been a formal manager with direct reports yet. But at Yelp I mentored junior engineers, onboarded new people, wrote runbooks and led knowledge sharing. A team of five is a good size for me, I can coach and still be hands-on.&lt;/p&gt;

&lt;p&gt;How would you lead senior engineers?&lt;br&gt;
I would not micromanage. I give clear goals and priorities, and each senior person owns one area, like Terraform, CI/CD or EKS. I stay hands-on with them on hard problems. Senior people want trust and direction, not control.&lt;/p&gt;

&lt;p&gt;How do you resolve conflict between two engineers?&lt;br&gt;
I bring both together and let each explain without interrupting. We go back to the goal, cost, security, reliability or time. I ask for facts, data or a small proof of concept. If they still disagree, I decide, explain why, and write it down. Then we disagree and commit. At Yelp two engineers disagreed on speed versus safety, and we chose blue-green with automatic rollback, which gave us 35 percent faster deployments.&lt;/p&gt;

&lt;p&gt;One engineer is not meeting expectations, what do you do?&lt;br&gt;
Private one on one first, I listen and ask what is going on. Then I make expectations clear with examples and small goals with dates. I give support, pair them with a strong engineer and remove blockers. Weekly check-ins. If no progress, I work with HR on a fair, documented plan.&lt;/p&gt;

&lt;p&gt;How do you prioritize when everything is urgent?&lt;br&gt;
Business impact and risk. Production and security issues first, then work that unblocks app teams, then improvements. I agree on top priorities with my manager every week so the team is not pulled in many directions.&lt;/p&gt;

&lt;p&gt;How do you report to leadership?&lt;br&gt;
Short and simple. A monthly update with roadmap, risks, cloud cost trend, and a few metrics like deployment frequency, failed changes, incidents and time to recover.&lt;/p&gt;

&lt;p&gt;How do you handle an outage as the escalation point?&lt;br&gt;
First stop the impact with rollback or failover. Update people every 30 minutes. One person leads, others fix. After, a blameless postmortem with clear action items and owners.&lt;/p&gt;

&lt;p&gt;TECHNICAL ANSWERS FROM ROUND ONE&lt;/p&gt;

&lt;p&gt;Recent architecture you deployed?&lt;br&gt;
At Zulily, an app on EKS with DocumentDB. VPC across multiple availability zones. Public subnets only for the load balancer, private subnets for EKS nodes and the database. Route 53 to the load balancer with TLS, then to pods. DocumentDB is private, only the app security group can reach it, IAM least privilege. HPA adds pods, Cluster Autoscaler adds nodes, so it grows during sales and shrinks after. Everything in Terraform modules, same code for dev, staging and prod. GitHub Actions with tests, terraform plan review and approval before prod. CloudWatch for alerts.&lt;/p&gt;

&lt;p&gt;Kubernetes experience?&lt;br&gt;
Four years on EKS at Yelp and now Zulily, CKAD certified. Helm charts so every team deploys the same way. Liveness and readiness probes for self-healing. HPA and Cluster Autoscaler. I troubleshoot CrashLoopBackOff, image pull errors and resource limits with kubectl describe, logs and events.&lt;/p&gt;

&lt;p&gt;EKS versus ECS Fargate?&lt;br&gt;
EKS fits many microservices, more control, Helm, one deployment pattern. Fargate fits small apps, no nodes to manage, less work. My hands-on is EKS, ECS is new for me but the ideas are very close.&lt;/p&gt;

&lt;p&gt;Event based architecture and Lambda?&lt;br&gt;
Services do not call each other directly, one sends an event and others react. EventBridge routes events, SNS sends to many, SQS queues so nothing is lost, Lambda runs code when an event comes. Watch the 15 minute timeout, memory, cold starts, IAM role, dead letter queues, and make processing safe to run twice. I am familiar, but have not built big systems myself.&lt;/p&gt;

&lt;p&gt;Identity?&lt;br&gt;
AWS IAM roles and least privilege. GitHub Actions deploys with IAM roles, no long term keys. IAM roles for Kubernetes service accounts on EKS. Okta and Active Directory I know the ideas, single sign on, MFA, groups mapped to AWS roles through IAM Identity Center.&lt;/p&gt;

&lt;p&gt;How do you use AI?&lt;br&gt;
Claude AI daily as a helper. Draft pipelines, review Terraform, explain errors, write documentation. Always review and test, never share secrets or customer data. I agree with your careful approach, start small, approved tools, human review, and guardrails like logging and access control.&lt;/p&gt;

&lt;p&gt;NEW TOPICS LIKELY IN ROUND TWO&lt;/p&gt;

&lt;p&gt;Landing zones&lt;br&gt;
Key words: AWS Organizations, Control Tower, separate accounts per environment, SCPs, central logging.&lt;br&gt;
Answer: A landing zone is the secure starting setup for all cloud accounts. Separate accounts for prod, non-prod, security and logging, with guardrails so teams cannot break the rules.&lt;/p&gt;

&lt;p&gt;Azure basics&lt;br&gt;
Key words: subscriptions, resource groups, VNet, AKS, Entra ID, Bicep.&lt;br&gt;
Answer: Azure is very similar to AWS. VNet is like VPC, AKS is like EKS, Entra ID is like IAM, Bicep is like CloudFormation. Terraform works on both.&lt;/p&gt;

&lt;p&gt;OCI basics&lt;br&gt;
Key words: tenancy, compartments, VCN, OKE.&lt;br&gt;
Answer: OCI uses compartments to organize resources, VCN is like VPC, OKE is their Kubernetes. Often used for Oracle databases and ERP.&lt;/p&gt;

&lt;p&gt;Terraform at scale&lt;br&gt;
Key words: modules, remote state, state locking, separate folders per environment, plan review in pull request.&lt;br&gt;
Answer: I already do this at Zulily with S3 state and DynamoDB locking. The same pattern works with Azure and OCI providers.&lt;/p&gt;

&lt;p&gt;Hybrid networking&lt;br&gt;
Key words: site to site VPN, Direct Connect, ExpressRoute, Transit Gateway, private DNS.&lt;br&gt;
Answer: It connects on-prem to cloud. VPN is quick and cheap, Direct Connect or ExpressRoute is private and faster for production.&lt;/p&gt;

&lt;p&gt;Disaster recovery&lt;br&gt;
Key words: RTO, RPO, backup and restore, pilot light, warm standby, multi-region.&lt;br&gt;
Answer: RTO is how fast we recover, RPO is how much data we can lose. We choose the strategy by business need and cost, and we test restores regularly.&lt;/p&gt;

&lt;p&gt;Cloud cost, FinOps&lt;br&gt;
Key words: tagging, right-sizing, Savings Plans, Reserved Instances, spot, Cost Explorer, budgets and alerts.&lt;br&gt;
Answer: First tag everything so we know who spends what. Then right-size, turn off unused dev at night, Savings Plans for steady work, spot for flexible work. Monthly cost report to leadership.&lt;/p&gt;

&lt;p&gt;Security&lt;br&gt;
Key words: Secrets Manager, KMS encryption, GuardDuty, Security Hub, image scanning, CIS benchmarks.&lt;br&gt;
Answer: Least privilege, encrypt everything, no secrets in code, scan images in the pipeline, and work with the security team to fix findings by priority.&lt;/p&gt;

&lt;p&gt;Observability&lt;br&gt;
Key words: metrics, logs, traces, CloudWatch, Datadog, Prometheus and Grafana, alert fatigue.&lt;br&gt;
Answer: Alert only on what users feel, every alert has a runbook, same dashboards across clouds.&lt;/p&gt;

&lt;p&gt;Self-service platform&lt;br&gt;
Key words: golden path, pipeline templates, Helm and Terraform modules, developer portal like Backstage.&lt;br&gt;
Answer: App teams get a standard template and can deploy alone, the platform team keeps guardrails. This fixes the pipeline confusion they told us about.&lt;/p&gt;

&lt;p&gt;Vendors and managed services&lt;br&gt;
Key words: SLAs, quarterly reviews, cost, escalation path.&lt;br&gt;
Answer: Clear SLAs, regular review meetings, and our team still understands what the vendor runs.&lt;/p&gt;

&lt;p&gt;HONEST GAP ANSWERS&lt;/p&gt;

&lt;p&gt;Pattern for every gap: say honestly you have not done it in production, show you know the idea, connect it to something you did, end with how fast you learn.&lt;/p&gt;

&lt;p&gt;Formal manager: Not formal yet, but mentoring, onboarding, runbooks and knowledge sharing at Yelp. Ready for the next step.&lt;br&gt;
Azure and OCI: Not in production, my work is AWS. Concepts map one to one and Terraform works on all three, so I can be productive fast.&lt;br&gt;
Bicep and CloudFormation: Terraform is my main tool. Same idea, declare resources, review the plan, deploy.&lt;br&gt;
ECS: Hands-on is EKS. ECS task definitions and services are close to Kubernetes deployments.&lt;br&gt;
Active Directory and Okta: Not managed them, but I know single sign on, MFA, groups mapped to cloud roles. Strong IAM background.&lt;br&gt;
Event driven and Lambda at scale: Familiar, not built big systems. I can support it with Terraform, IAM and monitoring.&lt;br&gt;
FinOps and DR ownership: Have not owned it fully, familiar with right-sizing, Savings Plans, backup and restore testing, RTO and RPO.&lt;br&gt;
Vendor management: Not owned vendor contracts yet, but I know the basics, clear SLAs and regular reviews.&lt;/p&gt;

&lt;p&gt;30 60 90 DAY PLAN&lt;/p&gt;

&lt;p&gt;First 30 days, listen and learn. One on one with each of the 5 engineers and the other manager. Sit with app teams and watch where they get stuck with pipelines. Review the AWS, Azure and OCI setup, Terraform code, incidents and cloud cost. Write a gap list and agree on top priorities with my manager.&lt;/p&gt;

&lt;p&gt;Days 31 to 60, quick wins and structure. Weekly planning and a short daily sync so work is visible. Each senior engineer owns one area. Simple design doc and weekly design review for bigger decisions. First standard pipeline template for app teams.&lt;/p&gt;

&lt;p&gt;Days 61 to 90, scale it. Golden path documentation and runbooks so app teams onboard alone. Monthly report to leadership with roadmap, risks, cost and delivery metrics. Plan for cost tagging, DR testing and safe AI tools.&lt;/p&gt;

&lt;p&gt;QUESTIONS TO ASK&lt;/p&gt;

&lt;p&gt;Do not repeat what they already answered: team size, seniority, Okta, EKS and ECS, AI stage.&lt;/p&gt;

&lt;p&gt;For the hiring manager or director:&lt;br&gt;
What would make you say after 6 months, this was the right hire?&lt;br&gt;
How is work split between AWS, Azure and OCI, and is there a plan to consolidate?&lt;br&gt;
How does this role divide work with the other manager?&lt;br&gt;
What is the biggest risk on the platform today?&lt;/p&gt;

&lt;p&gt;For engineers on the team:&lt;br&gt;
What slows you down most in a normal week?&lt;br&gt;
How do app teams ask you for help today, tickets, Slack or meetings?&lt;br&gt;
What would you want from a new manager?&lt;/p&gt;

&lt;p&gt;For HR or recruiter:&lt;br&gt;
Is there relocation support for the move to Bonita Springs?&lt;br&gt;
Is there a leadership program for new managers?&lt;br&gt;
What are the next steps and timeline?&lt;/p&gt;

&lt;p&gt;LOGISTICS AND FINAL TIPS&lt;/p&gt;

&lt;p&gt;Relocation: have a clear yes and a realistic start date ready, because you live in Vancouver, WA and the job is on-site in Florida.&lt;br&gt;
Salary: research the range for cloud engineering managers in Southwest Florida and give a range, not one number.&lt;br&gt;
About Herc: they rent equipment to construction, industrial and event customers. Read their latest news the day before and mention one recent fact.&lt;br&gt;
Every answer: short, one real example, end with a question.&lt;br&gt;
Use their words back: structure, observe first, golden path for app teams, careful with AI. It shows you listened.&lt;br&gt;
Send a thank you email the same day and mention one thing you discussed.&lt;br&gt;
Practice the pitch out loud three times.&lt;br&gt;
Practice the Azure and OCI mapping to AWS.&lt;br&gt;
Prepare one outage story and one cost saving idea.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>cloud</category>
      <category>interview</category>
      <category>management</category>
    </item>
    <item>
      <title>JumpToTech DevOps/SRE Capstone Project EstateFlow — Enterprise AWS EKS Production Environment</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Fri, 06 Nov 2026 04:02:22 +0000</pubDate>
      <link>https://dev.to/jumptotech/jumptotech-devopssre-capstone-project-estateflow-enterprise-aws-eks-production-environment-54gl</link>
      <guid>https://dev.to/jumptotech/jumptotech-devopssre-capstone-project-estateflow-enterprise-aws-eks-production-environment-54gl</guid>
      <description>&lt;h2&gt;
  
  
  1. The complete architecture
&lt;/h2&gt;

&lt;p&gt;EstateFlow — target deployment architecture&lt;/p&gt;

&lt;p&gt;Conceptual architecture. The database and Redis shown here are lab workloads; production environments would normally require stronger availability, backups, and disaster-recovery design.&lt;/p&gt;

&lt;h3&gt;
  
  
  What students will actually implement
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;What students must explain&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;React + Node.js + PostgreSQL + Redis&lt;/td&gt;
&lt;td&gt;Request flow, API, database dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure&lt;/td&gt;
&lt;td&gt;Terraform, VPC, EKS, ECR, IAM&lt;/td&gt;
&lt;td&gt;Infrastructure as Code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI&lt;/td&gt;
&lt;td&gt;GitHub Actions, tests, SonarQube, Trivy&lt;/td&gt;
&lt;td&gt;Quality and security gates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CD&lt;/td&gt;
&lt;td&gt;Helm + Argo CD&lt;/td&gt;
&lt;td&gt;GitOps, drift, rollback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Networking&lt;/td&gt;
&lt;td&gt;Services, ALB, Ingress, DNS&lt;/td&gt;
&lt;td&gt;External and internal traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;RBAC, IAM, Pod Identity, NetworkPolicy&lt;/td&gt;
&lt;td&gt;Authorization and isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;StatefulSet, PVC, EBS CSI&lt;/td&gt;
&lt;td&gt;Persistence and recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduling&lt;/td&gt;
&lt;td&gt;Affinity, anti-affinity, taints, tolerations&lt;/td&gt;
&lt;td&gt;Pod placement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability&lt;/td&gt;
&lt;td&gt;HPA, PDB, probes, rolling updates&lt;/td&gt;
&lt;td&gt;Availability and scaling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operations&lt;/td&gt;
&lt;td&gt;Prometheus, Grafana, alerting&lt;/td&gt;
&lt;td&gt;Incident detection and diagnosis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incidents&lt;/td&gt;
&lt;td&gt;503, Pending, CrashLoopBackOff, PVC failures&lt;/td&gt;
&lt;td&gt;Root cause, mitigation, postmortem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Important architecture decisions
&lt;/h3&gt;

&lt;p&gt;For this lab, PostgreSQL and Redis run inside Kubernetes so students can learn StatefulSets, persistent volumes, and storage troubleshooting. For a higher-availability production design, I would normally evaluate Amazon RDS/Aurora and ElastiCache instead.&lt;/p&gt;

&lt;p&gt;We will demonstrate the built-in workload controllers and selected AWS controllers, not indiscriminately install every Kubernetes controller. Each controller must have a reason to exist.&lt;/p&gt;

&lt;p&gt;The application will have two deployment environments, &lt;code&gt;estateflow-staging&lt;/code&gt; and &lt;code&gt;estateflow-prod&lt;/code&gt;, plus dedicated infrastructure namespaces. We will only call the second one “prod” as a classroom environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Repository structure
&lt;/h2&gt;

&lt;p&gt;Students will use one application repository and one GitOps repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jumptotech-estateflow/
├── frontend/
│   ├── src/
│   ├── Dockerfile
│   ├── package.json
│   └── nginx.conf
├── backend/
│   ├── src/
│   │   ├── server.js
│   │   └── db.js
│   ├── tests/
│   ├── Dockerfile
│   └── package.json
├── database/
│   └── init.sql
├── terraform/
│   ├── versions.tf
│   ├── providers.tf
│   ├── main.tf
│   ├── variables.tf
│   ├── outputs.tf
│   └── terraform.tfvars.example
├── helm/
│   └── estateflow/
│       ├── Chart.yaml
│       ├── values.yaml
│       └── templates/
├── k8s/
│   ├── rbac/
│   ├── security/
│   ├── scheduling/
│   ├── autoscaling/
│   └── storage/
├── argocd/
├── monitoring/
├── incidents/
├── scripts/
├── docs/
├── .github/
│   └── workflows/
├── docker-compose.yml
└── README.md

jumptotech-estateflow-gitops/
├── applications/
├── environments/
│   ├── staging/
│   └── prod/
└── charts/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use the following naming conventions consistently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;AWS_REGION&lt;/span&gt;=&lt;span class="n"&gt;us&lt;/span&gt;-&lt;span class="n"&gt;east&lt;/span&gt;-&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;CLUSTER_NAME&lt;/span&gt;=&lt;span class="n"&gt;estateflow&lt;/span&gt;-&lt;span class="n"&gt;lab&lt;/span&gt;
&lt;span class="n"&gt;APP_NAME&lt;/span&gt;=&lt;span class="n"&gt;estateflow&lt;/span&gt;
&lt;span class="n"&gt;STAGING_NAMESPACE&lt;/span&gt;=&lt;span class="n"&gt;estateflow&lt;/span&gt;-&lt;span class="n"&gt;staging&lt;/span&gt;
&lt;span class="n"&gt;PROD_NAMESPACE&lt;/span&gt;=&lt;span class="n"&gt;estateflow&lt;/span&gt;-&lt;span class="n"&gt;prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original &lt;code&gt;payments-incident-lab&lt;/code&gt; must not be included in any cleanup script.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Phase 0 — Environment and safety checks
&lt;/h2&gt;

&lt;p&gt;Every student runs these commands before provisioning anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nt"&gt;--version&lt;/span&gt;
docker &lt;span class="nt"&gt;--version&lt;/span&gt;
aws &lt;span class="nt"&gt;--version&lt;/span&gt;
kubectl version &lt;span class="nt"&gt;--client&lt;/span&gt;
terraform version
helm version &lt;span class="nt"&gt;--short&lt;/span&gt;

aws sts get-caller-identity
aws configure get region

kubectl config get-contexts
kubectl get namespaces
kubectl get nodes &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Students must confirm they are using their intended AWS account.&lt;/p&gt;

&lt;p&gt;Cost warning: EKS, EC2 worker nodes, load balancers, EBS volumes, NAT gateways, public IPv4 addresses, and monitoring resources can incur charges. The cluster must be deliberately sized and destroyed after the project. A multi-AZ production-like environment is not a free-tier lab.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Phase 1 — Create the application
&lt;/h2&gt;

&lt;p&gt;We will first build a working backend and frontend locally. Kubernetes must not be used to hide application defects.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 Backend — Node.js API
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; jumptotech-estateflow/backend/src
&lt;span class="nb"&gt;cd &lt;/span&gt;jumptotech-estateflow/backend

&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; package.json &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
{
  "name": "estateflow-backend",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node src/server.js",
    "test": "node --test"
  },
  "dependencies": {
    "express": "^4.21.2",
    "pg": "^8.13.1",
    "redis": "^4.7.0",
    "prom-client": "^15.1.3"
  }
}
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;backend/src/server.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pg&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;redis&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prom-client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_HOST&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_NAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;estateflow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_USER&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;estateflow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;connectionTimeoutMillis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;redis://localhost:6379&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;reconnectStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Redis error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collectDefaultMetrics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;httpRequests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;estateflow_http_requests_total&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Total HTTP requests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;labelNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;method&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;route&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;httpRequests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/healthz&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/readyz&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/db-check&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reachable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Database check failed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;database unavailable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/properties&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT id, title, city, price FROM properties ORDER BY id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Property query failed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;database unavailable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/bookings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;propertyId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;property_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;propertyId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;propertyId&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
      &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invalid booking request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`INSERT INTO bookings(property_id, customer_name)
       VALUES ($1, $2)
       RETURNING id, property_id, customer_name, status`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;propertyId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Booking failed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;booking unavailable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/cache-check&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reachable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Redis check failed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cache unavailable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/metrics&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EstateFlow API listening on port 8080&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Teaching point: &lt;code&gt;/healthz&lt;/code&gt; and &lt;code&gt;/readyz&lt;/code&gt; deliberately do not require database access. A database failure can therefore produce HTTP 503 on business endpoints while Pods remain Running and Ready. This is central to our incident scenario.&lt;/p&gt;

&lt;p&gt;For an actual production application, readiness behavior must be designed around whether a Pod can serve its intended traffic; this simplified probe is chosen to demonstrate dependency failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Database schema
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;database/init.sql&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;bookings&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;property_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
      &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Chicago Downtown Apartment'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Chicago'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Schaumburg Family House'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Schaumburg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3200&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Naperville Townhome'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Naperville'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2800&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For repeated initialization, students should ensure seed data is not inserted twice; a later database migration will replace this development seed.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 Backend Dockerfile
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;backend/Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:22-alpine&lt;/span&gt;

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

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src ./src&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; NODE_ENV=production&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "src/server.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.4 Frontend
&lt;/h3&gt;

&lt;p&gt;Create the React application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../

npm create vite@latest frontend &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts

&lt;span class="nb"&gt;cd &lt;/span&gt;frontend
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;frontend/src/App.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Property&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProperties&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Property&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/properties&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API unavailable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setProperties&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unable to load properties&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;book&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/bookings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;property_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Lab Student&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Booking submitted successfully&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Booking service unavailable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;850&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;EstateFlow&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Find your next home.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid #ccc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; — $&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/month&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;book&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Request booking
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;frontend/nginx.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/usr/share/nginx/html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="n"&gt;/index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/healthz&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="s"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/api/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://backend:8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt;
            &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;backend&lt;/code&gt; hostname above is for local Docker Compose. In Kubernetes, the frontend configuration will use the &lt;code&gt;estateflow-api&lt;/code&gt; Service name.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;frontend/Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:22-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginxinc/nginx-unprivileged:stable-alpine&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; nginx.conf /etc/nginx/conf.d/default.conf&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/dist /usr/share/nginx/html&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.5 Local Docker Compose
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;docker-compose.yml&lt;/code&gt; in the repository root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local-dev-only&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres_data:/var/lib/postgresql/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./database/init.sql:/docker-entrypoint-initdb.d/init.sql:ro&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;estateflow"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;

  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7-alpine&lt;/span&gt;

  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./backend&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;DB_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
      &lt;span class="na"&gt;DB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
      &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local-dev-only&lt;/span&gt;
      &lt;span class="na"&gt;REDIS_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis://redis:6379&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
      &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_started&lt;/span&gt;

  &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./frontend&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8088:8080"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;--build&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;

curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8088/healthz

curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8088/api/properties

curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8088/api/db-check

curl &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  http://localhost:8088/api/bookings &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"property_id":1,"customer_name":"JumpToTech Student"}'&lt;/span&gt;

docker compose ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected healthy baseline: frontend HTTP 200, property list HTTP 200, database check HTTP 200, booking HTTP 201.&lt;/p&gt;

&lt;p&gt;The students must save the actual responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Phase 2 — Terraform and AWS infrastructure
&lt;/h2&gt;

&lt;p&gt;We will create a separate EKS cluster named &lt;code&gt;estateflow-lab&lt;/code&gt;, rather than risking the existing training cluster.&lt;/p&gt;

&lt;p&gt;For classroom work, use a dedicated AWS account if possible. The reference infrastructure uses two Availability Zones, managed node groups, ECR, and EKS Pod Identity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform provider
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;terraform/versions.tf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 1.6.0"&lt;/span&gt;

  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/aws"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 6.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;terraform/providers.tf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_region&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;terraform/variables.tf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"aws_region"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cluster_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"estateflow-lab"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"student_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  VPC, EKS and ECR
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;terraform/main.tf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_availability_zones"&lt;/span&gt; &lt;span class="s2"&gt;"available"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"available"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;student_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nx"&gt;azs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_availability_zones&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;available&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Project&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"EstateFlow"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"training"&lt;/span&gt;
    &lt;span class="nx"&gt;ManagedBy&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Terraform"&lt;/span&gt;
    &lt;span class="nx"&gt;Owner&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;student_id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"vpc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-aws-modules/vpc/aws"&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 6.0"&lt;/span&gt;

  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-vpc"&lt;/span&gt;
  &lt;span class="nx"&gt;cidr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10.60.0.0/16"&lt;/span&gt;

  &lt;span class="nx"&gt;azs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azs&lt;/span&gt;

  &lt;span class="nx"&gt;private_subnets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"10.60.1.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"10.60.2.0/24"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;public_subnets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"10.60.101.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"10.60.102.0/24"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;enable_nat_gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;single_nat_gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;public_subnet_tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"kubernetes.io/role/elb"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;private_subnet_tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"kubernetes.io/role/internal-elb"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"eks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-aws-modules/eks/aws"&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 21.0"&lt;/span&gt;

  &lt;span class="nx"&gt;name&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;kubernetes_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1.34"&lt;/span&gt;

  &lt;span class="nx"&gt;endpoint_public_access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;enable_cluster_creator_admin_permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;module&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_id&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnets&lt;/span&gt;

  &lt;span class="nx"&gt;addons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;coredns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nx"&gt;kube-proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nx"&gt;vpc-cni&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;before_compute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="nx"&gt;configuration_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;enableNetworkPolicy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"true"&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;eks-pod-identity-agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nx"&gt;aws-ebs-csi-driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;most_recent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;eks_managed_node_groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;general&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;instance_types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"t3.large"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="nx"&gt;min_size&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
      &lt;span class="nx"&gt;max_size&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
      &lt;span class="nx"&gt;desired_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

      &lt;span class="nx"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;workload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"general"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ecr_repository"&lt;/span&gt; &lt;span class="s2"&gt;"frontend"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-frontend"&lt;/span&gt;
  &lt;span class="nx"&gt;image_tag_mutability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IMMUTABLE"&lt;/span&gt;

  &lt;span class="nx"&gt;image_scanning_configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;scan_on_push&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ecr_repository"&lt;/span&gt; &lt;span class="s2"&gt;"backend"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-backend"&lt;/span&gt;
  &lt;span class="nx"&gt;image_tag_mutability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IMMUTABLE"&lt;/span&gt;

  &lt;span class="nx"&gt;image_scanning_configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;scan_on_push&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;terraform/outputs.tf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"cluster_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"frontend_repository"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_ecr_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository_url&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"backend_repository"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_ecr_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository_url&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;terraform/terraform.tfvars.example&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;aws_region&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="nx"&gt;cluster_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"estateflow-lab"&lt;/span&gt;
&lt;span class="nx"&gt;student_id&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"student01"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before applying: Confirm the requested Kubernetes version is currently supported by EKS and compatible with the selected add-ons, AWS provider, and Terraform module. The example version is a starting target, not a substitute for compatibility validation.&lt;/p&gt;

&lt;p&gt;The initial lab uses a single NAT gateway to limit cost. This is not a fully resilient multi-AZ NAT design. For a higher-availability deployment, use appropriate per-AZ egress architecture or VPC endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;terraform

&lt;span class="nb"&gt;cp &lt;/span&gt;terraform.tfvars.example terraform.tfvars

terraform init

terraform &lt;span class="nb"&gt;fmt&lt;/span&gt; &lt;span class="nt"&gt;-recursive&lt;/span&gt;

terraform validate

terraform plan &lt;span class="nt"&gt;-out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;estateflow.tfplan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instructor approval checkpoint: Review cost, AWS quotas, subnet allocation, cluster version, add-on permissions, node capacity, and Terraform plan before applying.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform apply estateflow.tfplan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws eks update-kubeconfig &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; STUDENT01-estateflow-lab

kubectl get nodes &lt;span class="nt"&gt;-o&lt;/span&gt; wide

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system

kubectl get daemonsets &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the cluster name with the exact Terraform output; it will include the student's identifier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure items that must be completed before application deployment
&lt;/h3&gt;

&lt;p&gt;The Terraform baseline above is not yet the entire AWS platform. Students must also configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EBS CSI driver IAM permissions through EKS Pod Identity or a supported IAM integration.&lt;/li&gt;
&lt;li&gt;AWS Load Balancer Controller IAM role, Pod Identity association, Helm installation, and webhook readiness.&lt;/li&gt;
&lt;li&gt;GitHub Actions OIDC identity with narrowly scoped ECR push permissions.&lt;/li&gt;
&lt;li&gt;ECR lifecycle policies and image retention.&lt;/li&gt;
&lt;li&gt;Terraform remote state in an S3 backend with locking and encryption.&lt;/li&gt;
&lt;li&gt;Restricted EKS API access, rather than leaving unrestricted public endpoint access for production.&lt;/li&gt;
&lt;li&gt;DNS, TLS certificates, and ALB listener rules.&lt;/li&gt;
&lt;li&gt;Worker-node sizing for monitoring, Argo CD, database, and application workloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not assume that creating the EKS cluster automatically installs the AWS Load Balancer Controller or grants EBS CSI storage permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Phase 3 — Kubernetes workloads
&lt;/h2&gt;

&lt;p&gt;First create the application namespaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace estateflow-staging
kubectl create namespace estateflow-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not deploy the same StatefulSet database to both environments using shared volumes. Each environment must have its own data and storage.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 PostgreSQL StatefulSet
&lt;/h3&gt;

&lt;p&gt;Save as &lt;code&gt;k8s/storage/postgres.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;StatefulSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;serviceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-db&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PGDATA&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/postgresql/data/pgdata&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-data&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/postgresql/data&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sh&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;-c&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pg_isready -U estateflow -d estateflow&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;128Mi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;512Mi&lt;/span&gt;
  &lt;span class="na"&gt;volumeClaimTemplates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-data&lt;/span&gt;
      &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&lt;/span&gt;
        &lt;span class="na"&gt;storageClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gp3&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a database password without storing it in Git:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"DB_PASSWORD?Database password: "&lt;/span&gt;
&lt;span class="nb"&gt;echo

&lt;/span&gt;kubectl create secret generic estateflow-db &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB_PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;unset &lt;/span&gt;DB_PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a classroom deployment, this is acceptable as an introductory Secret exercise. In a production design, use an external secret-management solution, encryption controls, and rotation. Do not commit Secret manifests containing plaintext passwords.&lt;/p&gt;

&lt;p&gt;Before applying the StatefulSet, verify that the &lt;code&gt;gp3&lt;/code&gt; StorageClass exists and that the EBS CSI driver is authorized:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get storageclass

kubectl get csidrivers

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system | &lt;span class="nb"&gt;grep &lt;/span&gt;ebs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;gp3&lt;/code&gt; is absent, create a CSI-backed StorageClass with &lt;code&gt;ebs.csi.aws.com&lt;/code&gt;, appropriate binding mode, and encryption. Do not proceed until the storage controller is operational.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; k8s/storage/postgres.yaml

kubectl get statefulsets &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl get pvc &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instructor explanation: StatefulSet gives PostgreSQL a stable identity and persistent volume association. It does not automatically provide database replication, backups, or high availability. Our single-replica PostgreSQL is deliberately a learning environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.2 Redis StatefulSet
&lt;/h3&gt;

&lt;p&gt;Create a separate Redis StatefulSet with one replica, its own headless Service, persistent volume, and resource limits. Redis must not share the PostgreSQL PVC.&lt;/p&gt;

&lt;p&gt;Students must explain why Redis is not the source of truth for booking records.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.3 Backend Deployment and Service
&lt;/h3&gt;

&lt;p&gt;Save as &lt;code&gt;k8s/backend.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
    &lt;span class="na"&gt;rollingUpdate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;maxSurge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;maxUnavailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REPLACE_WITH_BACKEND_ECR_IMAGE&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
              &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_HOST&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_NAME&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_USER&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-db&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis://estateflow-redis:6379&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/readyz&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/healthz&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
          &lt;span class="na"&gt;startupProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/healthz&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
            &lt;span class="na"&gt;failureThreshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;128Mi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;512Mi&lt;/span&gt;
          &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
            &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;drop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALL"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the image placeholder with the actual immutable ECR image URI before applying. The final GitOps deployment will use Helm rather than manually editing this file.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.4 Frontend Deployment
&lt;/h3&gt;

&lt;p&gt;The frontend needs a separate Deployment and ClusterIP Service.&lt;/p&gt;

&lt;p&gt;Use three initial replicas for the classroom deployment only if node capacity allows. Configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Port 8080&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/healthz&lt;/code&gt; readiness and liveness checks&lt;/li&gt;
&lt;li&gt;Resource requests and limits&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RollingUpdate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Pod anti-affinity or topology spread&lt;/li&gt;
&lt;li&gt;A Service named &lt;code&gt;estateflow-frontend&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Kubernetes NGINX configuration must proxy &lt;code&gt;/api/&lt;/code&gt; to &lt;code&gt;http://estateflow-api:8080&lt;/code&gt;, not to the Docker Compose hostname &lt;code&gt;backend&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.5 HPA
&lt;/h3&gt;

&lt;p&gt;Save as &lt;code&gt;k8s/autoscaling/api-hpa.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HorizontalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api-hpa&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Resource&lt;/span&gt;
      &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cpu&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Utilization&lt;/span&gt;
          &lt;span class="na"&gt;averageUtilization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl top nodes
kubectl top pods &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If metrics are unavailable, fix Metrics Server before expecting CPU-based HPA scaling.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.6 PodDisruptionBudget
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;k8s/autoscaling/api-pdb.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;policy/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PodDisruptionBudget&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api-pdb&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minAvailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explain that a PDB limits certain voluntary disruptions, such as node drains. It does not prevent all crashes, node failures, or application bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.7 Scheduling — affinity, taints and tolerations
&lt;/h3&gt;

&lt;p&gt;Add this to a workload Pod specification only when the cluster has eligible nodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;affinity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podAntiAffinity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;preferredDuringSchedulingIgnoredDuringExecution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
        &lt;span class="na"&gt;podAffinityTerm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;labelSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
          &lt;span class="na"&gt;topologyKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubernetes.io/hostname&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For AZ distribution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;topologySpreadConstraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;maxSkew&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;topologyKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;topology.kubernetes.io/zone&lt;/span&gt;
    &lt;span class="na"&gt;whenUnsatisfiable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ScheduleAnyway&lt;/span&gt;
    &lt;span class="na"&gt;labelSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the taints lab, create a separate dedicated node group before applying any taint.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl taint node NODE_NAME &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;dedicated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;estateflow:NoSchedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Matching Pod toleration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tolerations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dedicated&lt;/span&gt;
    &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Equal&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
    &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NoSchedule&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A toleration allows scheduling onto a tainted node; it does not force scheduling there. To target that node group, use appropriate node affinity or a node selector as well.&lt;/p&gt;

&lt;p&gt;Never taint the only available worker node in a shared classroom cluster. That could disrupt CoreDNS, monitoring, and other workloads.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.8 NetworkPolicy
&lt;/h3&gt;

&lt;p&gt;The application requires a deliberate communication model:&lt;/p&gt;

&lt;p&gt;Frontend&lt;/p&gt;

&lt;p&gt;Backend API&lt;/p&gt;

&lt;p&gt;PostgreSQL&lt;/p&gt;

&lt;p&gt;Frontend&lt;/p&gt;

&lt;p&gt;Direct PostgreSQL access&lt;/p&gt;

&lt;p&gt;NetworkPolicy controls permitted network traffic. It does not delete Pod IP addresses or remove Pods.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;k8s/security/postgres-networkpolicy.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-allow-api-only&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
          &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isolates PostgreSQL ingress and permits connections from matching API Pods in the same namespace. Other applicable policies can add permissions, so inspect all NetworkPolicies before claiming isolation.&lt;/p&gt;

&lt;p&gt;On AWS EKS, NetworkPolicy enforcement requires a compatible network-policy-capable implementation. With AWS VPC CNI, verify that NetworkPolicy support is enabled and the policy agent is running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get daemonset aws-node &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system

kubectl get networkpolicy &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl describe networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  postgres-allow-api-only &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.9 RBAC
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;k8s/rbac/read-only.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-observer&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Role&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-read-only&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pods"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;services"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;events"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;verbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;watch"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deployments"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replicasets"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;verbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;watch"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RoleBinding&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-observer-binding&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;subjects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-observer&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;roleRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Role&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-read-only&lt;/span&gt;
  &lt;span class="na"&gt;apiGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl auth can-i list pods &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--as&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;system:serviceaccount:estateflow-staging:estateflow-observer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl auth can-i delete pods &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--as&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;system:serviceaccount:estateflow-staging:estateflow-observer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected: listing allowed, deletion denied.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.10 IAM and Pod Identity
&lt;/h3&gt;

&lt;p&gt;Students must distinguish:&lt;/p&gt;

&lt;p&gt;Kubernetes RBAC controls what an identity can do through the Kubernetes API.&lt;/p&gt;

&lt;p&gt;AWS IAM controls access to AWS APIs and resources.&lt;/p&gt;

&lt;p&gt;EKS Pod Identity allows an authorized Kubernetes ServiceAccount to obtain AWS credentials through an IAM role association.&lt;/p&gt;

&lt;p&gt;For the lab, create a dedicated ServiceAccount for a workload that reads a narrowly scoped S3 object or CloudWatch resource. Associate it with a least-privilege IAM role using Terraform and EKS Pod Identity. Do not grant application Pods administrator permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.11 Ingress and AWS ALB
&lt;/h3&gt;

&lt;p&gt;After the AWS Load Balancer Controller is installed and healthy, create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-ingress&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;alb.ingress.kubernetes.io/scheme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;internet-facing&lt;/span&gt;
    &lt;span class="na"&gt;alb.ingress.kubernetes.io/target-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ip&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alb&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
                &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-frontend&lt;/span&gt;
                &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ALB controller reconciles this Ingress into AWS load-balancer resources. The ALB routes requests to the selected backend target group. The Kubernetes Service defines the backend Pods; the exact packet forwarding depends on the chosen target mode and networking implementation.&lt;/p&gt;

&lt;p&gt;Before calling this production-ready, add HTTPS, an ACM certificate, Route 53 DNS, access logs, health-check configuration, and appropriate security groups.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Phase 4 — GitHub Actions CI
&lt;/h2&gt;

&lt;p&gt;The delivery sequence will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer opens Pull Request
          |
          v
    GitHub Actions
          |
          +-- npm install / test / build
          |
          +-- SonarQube quality analysis
          |
          +-- Trivy vulnerability scan
          |
          v
     Merge approved
          |
          v
    Build Docker images
          |
          v
    Push to Amazon ECR
          |
          v
   Update GitOps image tags
          |
          v
      Argo CD sync
          |
          v
     Kubernetes rollout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GitHub permissions
&lt;/h3&gt;

&lt;p&gt;Create an AWS IAM role that trusts GitHub's OIDC provider. Restrict its trust policy to the intended repository, branch or GitHub environment, and audience &lt;code&gt;sts.amazonaws.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Grant only the ECR permissions required to authenticate and push to the two EstateFlow repositories.&lt;/p&gt;

&lt;p&gt;Do not put AWS access keys in GitHub Secrets. Use OIDC federation.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI workflow
&lt;/h3&gt;

&lt;p&gt;Save as &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

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

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

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22"&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
          &lt;span class="na"&gt;cache-dependency-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend/package-lock.json&lt;/span&gt;

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

  &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22"&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
          &lt;span class="na"&gt;cache-dependency-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend/package-lock.json&lt;/span&gt;

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

  &lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Trivy filesystem scan&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aquasecurity/trivy-action@0.33.1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;scan-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fs&lt;/span&gt;
          &lt;span class="na"&gt;scan-ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HIGH,CRITICAL&lt;/span&gt;
          &lt;span class="na"&gt;exit-code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend currently has no committed test suite. Before making &lt;code&gt;npm test&lt;/code&gt; a required branch-protection check, students must add tests for &lt;code&gt;/healthz&lt;/code&gt;, input validation, and booking/database error handling.&lt;/p&gt;

&lt;p&gt;For a production pipeline, pin GitHub Actions to reviewed commit SHAs and establish dependency-update procedures.&lt;/p&gt;

&lt;h3&gt;
  
  
  SonarQube
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;sonar-project.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;sonar.projectKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;estateflow&lt;/span&gt;
&lt;span class="py"&gt;sonar.projectName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;EstateFlow&lt;/span&gt;
&lt;span class="py"&gt;sonar.sources&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;frontend/src,backend/src&lt;/span&gt;
&lt;span class="py"&gt;sonar.sourceEncoding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;UTF-8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure a SonarQube server, token, and quality gate. Add a dedicated CI job that runs SonarScanner and waits for the quality-gate result.&lt;/p&gt;

&lt;p&gt;Students must understand that SonarQube performs static code analysis; it does not replace unit tests, dependency scanning, image scanning, or runtime monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  CD — ECR push workflow
&lt;/h3&gt;

&lt;p&gt;After CI passes on &lt;code&gt;main&lt;/code&gt;, a protected publishing workflow must:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Assume the AWS IAM role through GitHub OIDC.&lt;/li&gt;
&lt;li&gt;Authenticate to ECR.&lt;/li&gt;
&lt;li&gt;Build both Docker images.&lt;/li&gt;
&lt;li&gt;Scan the built images.&lt;/li&gt;
&lt;li&gt;Push immutable image tags derived from the Git commit SHA.&lt;/li&gt;
&lt;li&gt;Record the image digests.&lt;/li&gt;
&lt;li&gt;Open a pull request updating the GitOps repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example build commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FRONTEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_SHA&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ./frontend

docker build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_SHA&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ./backend

docker push &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FRONTEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_SHA&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

docker push &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_SHA&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These variables must be populated by the authenticated CI job. The image repositories must already exist.&lt;/p&gt;

&lt;p&gt;Important: Argo CD should not be given AWS credentials to build or push images. Its responsibility is reconciling the approved Kubernetes configuration from Git.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Phase 5 — Helm
&lt;/h2&gt;

&lt;p&gt;Helm packages the application's Kubernetes resources into reusable, parameterized charts.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm create helm/estateflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove or replace the generated example templates that do not match our application.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helm/estateflow/Chart.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v2&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EstateFlow Kubernetes application&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.1.0&lt;/span&gt;
&lt;span class="na"&gt;appVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;helm/estateflow/values.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REPLACE_FRONTEND_ECR_URI&lt;/span&gt;
    &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REPLACE_WITH_GIT_SHA&lt;/span&gt;

&lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REPLACE_BACKEND_ECR_URI&lt;/span&gt;
    &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REPLACE_WITH_GIT_SHA&lt;/span&gt;

&lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;128Mi&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;512Mi&lt;/span&gt;

&lt;span class="na"&gt;autoscaling&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
  &lt;span class="na"&gt;targetCPUUtilizationPercentage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;

&lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Students will convert the backend Deployment, frontend Deployment, Services, Ingress, HPA, PDB, and application configuration into Helm templates.&lt;/p&gt;

&lt;p&gt;Validate before deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm lint helm/estateflow

helm template estateflow &lt;span class="se"&gt;\&lt;/span&gt;
  helm/estateflow &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; estateflow-staging &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/estateflow-rendered.yaml

kubectl apply &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; /tmp/estateflow-rendered.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not use a Helm chart containing unreviewed duplicate resources already managed by Terraform or another controller.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Phase 6 — Argo CD GitOps
&lt;/h2&gt;

&lt;p&gt;Install Argo CD into its own namespace after checking cluster capacity and the supported installation version.&lt;/p&gt;

&lt;p&gt;Create an Argo CD Application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/YOUR_ORG/jumptotech-estateflow-gitops.git&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;charts/estateflow&lt;/span&gt;
    &lt;span class="na"&gt;helm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;valueFiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../../environments/staging/values.yaml&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;selfHeal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateNamespace=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The chart path and values-file path must be verified against the actual GitOps repository layout. A common simplification is to keep environment values inside the chart directory, avoiding cross-directory Helm value-file restrictions.&lt;/p&gt;

&lt;p&gt;For production-style operation, create an Argo CD AppProject with explicit source-repository, namespace, and resource restrictions instead of relying on the unrestricted default project.&lt;/p&gt;

&lt;p&gt;Students must verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get applications &lt;span class="nt"&gt;-n&lt;/span&gt; argocd

kubectl get deployments &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl rollout status deployment/estateflow-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Argo CD incident demonstration
&lt;/h3&gt;

&lt;p&gt;Change the approved image tag in the GitOps repository to a nonexistent tag.&lt;/p&gt;

&lt;p&gt;Expected possible result: new Pods enter &lt;code&gt;ImagePullBackOff&lt;/code&gt;, the rollout stalls, and Argo CD reports an unhealthy application.&lt;/p&gt;

&lt;p&gt;Restore the previous known-good image tag in Git, synchronize Argo CD, and verify the rollout.&lt;/p&gt;

&lt;p&gt;For GitOps-managed applications, the durable correction must be committed to Git. A manual &lt;code&gt;kubectl rollout undo&lt;/code&gt; may be overwritten by Argo CD reconciliation.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Phase 7 — Monitoring and alerting
&lt;/h2&gt;

&lt;p&gt;Install a compatible Prometheus Operator stack, including Prometheus, Grafana, and Alertmanager. If the existing classroom cluster already has monitoring, do not install a duplicate stack without checking capacity and ownership.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application metrics
&lt;/h3&gt;

&lt;p&gt;Our backend exposes:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Prometheus can scrape the backend using a ServiceMonitor when the operator and ServiceMonitor CRD are installed.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monitoring.coreos.com/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceMonitor&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;namespaceSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchNames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-api&lt;/span&gt;
  &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/metrics&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Service must expose a port named &lt;code&gt;http&lt;/code&gt; and have the matching label. The Prometheus instance must also be configured to select this ServiceMonitor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grafana dashboards
&lt;/h3&gt;

&lt;p&gt;Students will create dashboards showing:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;PromQL example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Available API replicas&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kube_deployment_status_replicas_available{namespace="estateflow-staging",deployment="estateflow-api"}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desired replicas&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kube_deployment_spec_replicas{namespace="estateflow-staging",deployment="estateflow-api"}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pod restarts&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sum(increase(kube_pod_container_status_restarts_total{namespace="estateflow-staging"}[5m]))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP 503 rate&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sum(rate(estateflow_http_requests_total{status="503"}[5m]))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API request rate&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sum(rate(estateflow_http_requests_total[5m]))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the application HTTP metrics, add the Prometheus scrape labels actually present in your deployment to avoid mixing staging and production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alerts
&lt;/h3&gt;

&lt;p&gt;Create alerts for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API HTTP 503 errors above a defined threshold.&lt;/li&gt;
&lt;li&gt;Available replicas below desired replicas.&lt;/li&gt;
&lt;li&gt;Persistent &lt;code&gt;CrashLoopBackOff&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Excessive Pod restarts.&lt;/li&gt;
&lt;li&gt;High CPU utilization.&lt;/li&gt;
&lt;li&gt;PostgreSQL connectivity failures.&lt;/li&gt;
&lt;li&gt;PVC capacity or availability issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A real SRE team should tune thresholds using observed traffic, error budgets, and service-level objectives. A classroom alert can be deliberately sensitive to make the incident visible.&lt;/p&gt;

&lt;h3&gt;
  
  
  PagerDuty
&lt;/h3&gt;

&lt;p&gt;Connect a dedicated training PagerDuty service through Alertmanager or Grafana.&lt;/p&gt;

&lt;p&gt;Students should experience the full sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prometheus detects condition
        ↓
Alertmanager / Grafana Alerting
        ↓
PagerDuty incident
        ↓
Primary on-call acknowledges
        ↓
Incident investigation
        ↓
Recovery verification
        ↓
Incident resolution
        ↓
Postmortem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not send classroom alerts to a real production on-call service.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Phase 8 — Main production incident: HTTP 503
&lt;/h2&gt;

&lt;p&gt;This is the incident every student will investigate and present in their capstone.&lt;/p&gt;

&lt;p&gt;SEV-1 training incident&lt;/p&gt;

&lt;p&gt;Service degraded&lt;/p&gt;

&lt;h2&gt;
  
  
  EstateFlow booking requests are failing
&lt;/h2&gt;

&lt;p&gt;Incident start&lt;/p&gt;

&lt;p&gt;2:13 AM — scenario&lt;/p&gt;

&lt;p&gt;Customer-facing symptom&lt;/p&gt;

&lt;p&gt;HTTP 503&lt;/p&gt;

&lt;p&gt;Kubernetes&lt;/p&gt;

&lt;p&gt;Pods Running / Ready&lt;/p&gt;

&lt;p&gt;Suspected dependency&lt;/p&gt;

&lt;p&gt;PostgreSQL&lt;/p&gt;

&lt;p&gt;The website is reachable, but booking requests cannot complete. The on-call engineer must identify the actual failure before attempting a rollback.&lt;/p&gt;

&lt;h3&gt;
  
  
  11.1 Incident team
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary SRE&lt;/td&gt;
&lt;td&gt;Acknowledge PagerDuty, investigate, coordinate recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incident Commander&lt;/td&gt;
&lt;td&gt;Set priorities, coordinate responders, maintain timeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend Engineer&lt;/td&gt;
&lt;td&gt;Review API behavior, exceptions, connection pools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DBA&lt;/td&gt;
&lt;td&gt;Verify PostgreSQL health, connectivity, and database state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud/Platform Engineer&lt;/td&gt;
&lt;td&gt;Investigate EKS, CNI, nodes, networking, IAM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security Engineer&lt;/td&gt;
&lt;td&gt;Review NetworkPolicies and security implications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release Engineer&lt;/td&gt;
&lt;td&gt;Review deployments, Argo CD history, recent changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Communications Lead&lt;/td&gt;
&lt;td&gt;Provide stakeholder updates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a small organization, one person may hold multiple roles. Students should learn the responsibilities, not assume every incident has eight people online.&lt;/p&gt;

&lt;h3&gt;
  
  
  11.2 Confirm healthy baseline
&lt;/h3&gt;

&lt;p&gt;Before injecting the failure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl get deployments &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl get endpointslices &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start a local port-forward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging &lt;span class="se"&gt;\&lt;/span&gt;
  svc/estateflow-api &lt;span class="se"&gt;\&lt;/span&gt;
  18080:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In another Terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:18080/healthz

curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:18080/readyz

curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:18080/api/db-check

curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:18080/api/properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected baseline: HTTP 200 on all four endpoints.&lt;/p&gt;

&lt;p&gt;Record the actual timestamp, screenshots, Pod names, Deployment revisions, and API responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  11.3 Introduce the controlled outage
&lt;/h3&gt;

&lt;p&gt;Only in &lt;code&gt;estateflow-staging&lt;/code&gt;, apply a NetworkPolicy that selects PostgreSQL and denies new ingress connections:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;incidents/01-block-postgres.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;incident-block-postgres&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-staging&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;estateflow-postgres&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important: If &lt;code&gt;postgres-allow-api-only&lt;/code&gt; is already present, this deny policy will not override it. Kubernetes NetworkPolicy allow rules are additive. For this controlled test, first inspect the existing policies and temporarily remove the allow policy through the approved staging change process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl describe networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  postgres-allow-api-only &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, after recording the original state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  postgres-allow-api-only &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl apply &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; incidents/01-block-postgres.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If Argo CD manages the policy, pause or coordinate reconciliation for this controlled experiment and restore the intended policy through GitOps afterward.&lt;/p&gt;

&lt;p&gt;Existing established database connections may survive policy changes temporarily. To test the failure reliably, force a new database connection from the application in the staging environment. Do not restart a production database or delete unrelated Pods.&lt;/p&gt;

&lt;h3&gt;
  
  
  11.4 Investigate the outage
&lt;/h3&gt;

&lt;p&gt;First check the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:18080/readyz

curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:18080/api/db-check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected result after enforcement and new connection attempts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /readyz
&lt;/span&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;

GET /api/db-check
HTTP/1.1 503 SERVICE UNAVAILABLE

{"error":"database unavailable"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now investigate Kubernetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; wide

kubectl describe deployment estateflow-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl logs &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging &lt;span class="se"&gt;\&lt;/span&gt;
  deployment/estateflow-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--all-pods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100

kubectl get networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl describe networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  incident-block-postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging

kubectl get events &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--sort-by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.lastTimestamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Students must identify the difference between a healthy Pod and a healthy business transaction.&lt;/p&gt;

&lt;p&gt;A Pod can be Running and Ready while its application cannot connect to PostgreSQL.&lt;/p&gt;

&lt;h3&gt;
  
  
  11.5 The incident investigation decision tree
&lt;/h3&gt;

&lt;p&gt;If the database is running and healthy, investigate connectivity and policy enforcement. If PostgreSQL itself is unhealthy, investigate storage, resource pressure, process logs, and database recovery instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  11.6 Communicate during the incident
&lt;/h3&gt;

&lt;p&gt;Students should practice realistic, concise communication.&lt;/p&gt;

&lt;p&gt;Initial PagerDuty acknowledgement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Acknowledged the EstateFlow booking failure alert. Investigating the HTTP 503 increase. Initial Kubernetes checks show the API Pods are Running and Ready. I am checking the database dependency and recent changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Message to the backend engineer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can you confirm whether the booking API is failing on database connection attempts? Please review recent application errors and connection-pool behavior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Message to the platform/security engineer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PostgreSQL appears healthy, but new API-to-database connections are failing. Please help verify NetworkPolicy enforcement, AWS VPC CNI policy-agent health, and any recent networking changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Incident Commander update:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We have isolated the failure to application connectivity with PostgreSQL. We are reviewing the active ingress policy and preparing a controlled restoration. Customer booking requests remain affected.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Only communicate findings that the team has actually verified.&lt;/p&gt;

&lt;h3&gt;
  
  
  11.7 Restore service
&lt;/h3&gt;

&lt;p&gt;Remove the incident policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  incident-block-postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; estateflow-staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restore the intended least-privilege allow policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; k8s/security/postgres-networkpolicy.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If Argo CD owns the policy, restore the approved GitOps manifest and verify synchronization.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://127.0.0.1:18080/api/db-check

curl &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  http://127.0.0.1:18080/api/bookings &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"property_id":1,"customer_name":"Recovery Test"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected after recovery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database check: HTTP 200
Booking creation: HTTP 201
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also verify the newly created booking exists in PostgreSQL, application error rates decline, and alerts return to normal.&lt;/p&gt;

&lt;p&gt;Do not close the incident based only on Pods showing &lt;code&gt;1/1 Running&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  11.8 Postmortem template
&lt;/h3&gt;

&lt;h1&gt;
  
  
  EstateFlow Incident Postmortem
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Incident ID:&lt;/strong&gt; EF-INC-001\&lt;br&gt;
&lt;strong&gt;Severity:&lt;/strong&gt; SEV-1 (training scenario)\&lt;br&gt;
&lt;strong&gt;Environment:&lt;/strong&gt; estateflow-staging\&lt;br&gt;
&lt;strong&gt;Incident Commander:&lt;/strong&gt; [Student / instructor]\&lt;br&gt;
&lt;strong&gt;Primary SRE:&lt;/strong&gt; [Student]&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The EstateFlow booking API experienced HTTP 503 errors because application-to-PostgreSQL connectivity was blocked by a Kubernetes NetworkPolicy.&lt;/p&gt;
&lt;h2&gt;
  
  
  Customer impact
&lt;/h2&gt;

&lt;p&gt;[Record which synthetic transactions failed, the observed error rate, and the duration measured during the lab.]&lt;/p&gt;
&lt;h2&gt;
  
  
  Detection
&lt;/h2&gt;

&lt;p&gt;The incident was detected through [Grafana alert / PagerDuty / synthetic monitoring]. Record the actual alert timestamp.&lt;/p&gt;
&lt;h2&gt;
  
  
  Timeline
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[Time]&lt;/td&gt;
&lt;td&gt;Healthy baseline verified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[Time]&lt;/td&gt;
&lt;td&gt;NetworkPolicy change applied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[Time]&lt;/td&gt;
&lt;td&gt;First HTTP 503 observed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[Time]&lt;/td&gt;
&lt;td&gt;Alert acknowledged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[Time]&lt;/td&gt;
&lt;td&gt;Application logs investigated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[Time]&lt;/td&gt;
&lt;td&gt;Root cause confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[Time]&lt;/td&gt;
&lt;td&gt;Policy corrected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[Time]&lt;/td&gt;
&lt;td&gt;HTTP 200 and booking HTTP 201 verified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[Time]&lt;/td&gt;
&lt;td&gt;Incident resolved&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Root cause
&lt;/h2&gt;

&lt;p&gt;A NetworkPolicy selected the PostgreSQL Pod and blocked new ingress connections from the EstateFlow API.&lt;/p&gt;

&lt;p&gt;The API's readiness endpoint did not depend on PostgreSQL, so Kubernetes continued reporting the application Pods as Ready even though database-dependent business requests failed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Mitigation
&lt;/h2&gt;

&lt;p&gt;The incident policy was removed and the intended least-privilege PostgreSQL access rule was restored.&lt;/p&gt;
&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Database check returned HTTP 200.&lt;/li&gt;
&lt;li&gt;Synthetic booking returned HTTP 201.&lt;/li&gt;
&lt;li&gt;Booking record was verified in PostgreSQL.&lt;/li&gt;
&lt;li&gt;Error-rate metrics recovered.&lt;/li&gt;
&lt;li&gt;Monitoring alerts resolved.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Preventive actions
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add NetworkPolicy connectivity tests before deployment.&lt;/li&gt;
&lt;li&gt;Require review of security-policy changes.&lt;/li&gt;
&lt;li&gt;Add synthetic booking monitoring.&lt;/li&gt;
&lt;li&gt;Improve runbooks for HTTP 503 investigation.&lt;/li&gt;
&lt;li&gt;Add GitOps validation and staged rollout controls.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Evidence
&lt;/h2&gt;

&lt;p&gt;Attach Terminal outputs, Grafana screenshots, PagerDuty event details, Git commit history, and recovery timestamps.&lt;/p&gt;
&lt;h2&gt;
  
  
  12. Phase 9 — Additional production-style incident labs
&lt;/h2&gt;

&lt;p&gt;After students complete the main outage, they must investigate the following scenarios. Every scenario must have its own baseline, failure injection, diagnosis, recovery, and evidence.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Incident&lt;/th&gt;
&lt;th&gt;Injected failure&lt;/th&gt;
&lt;th&gt;Primary investigation&lt;/th&gt;
&lt;th&gt;Expected recovery&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;01 — HTTP 503&lt;/td&gt;
&lt;td&gt;PostgreSQL NetworkPolicy block&lt;/td&gt;
&lt;td&gt;Logs, connectivity, policies&lt;/td&gt;
&lt;td&gt;Restore permitted DB traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;02 — ImagePullBackOff&lt;/td&gt;
&lt;td&gt;Invalid ECR image tag&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;describe pod&lt;/code&gt;, image URI, ECR&lt;/td&gt;
&lt;td&gt;Correct GitOps image reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;03 — CrashLoopBackOff&lt;/td&gt;
&lt;td&gt;Application exits on startup&lt;/td&gt;
&lt;td&gt;Pod logs, env, events&lt;/td&gt;
&lt;td&gt;Correct configuration/code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;04 — Readiness failure&lt;/td&gt;
&lt;td&gt;Invalid &lt;code&gt;/readyz&lt;/code&gt; probe path&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;describe pod&lt;/code&gt;, probe output&lt;/td&gt;
&lt;td&gt;Correct probe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;05 — HPA overload&lt;/td&gt;
&lt;td&gt;CPU pressure and insufficient capacity&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;kubectl top&lt;/code&gt;, HPA events&lt;/td&gt;
&lt;td&gt;Tune capacity and scaling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;06 — PVC Pending&lt;/td&gt;
&lt;td&gt;Unsupported StorageClass&lt;/td&gt;
&lt;td&gt;PVC events, CSI controller&lt;/td&gt;
&lt;td&gt;Restore correct storage configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;07 — Node NotReady&lt;/td&gt;
&lt;td&gt;Dedicated training node failure&lt;/td&gt;
&lt;td&gt;Node conditions, kubelet, events&lt;/td&gt;
&lt;td&gt;Recover/replace node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;08 — RBAC Forbidden&lt;/td&gt;
&lt;td&gt;Observer attempts unauthorized action&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kubectl auth can-i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Grant only justified permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09 — IAM AccessDenied&lt;/td&gt;
&lt;td&gt;Missing AWS role permission&lt;/td&gt;
&lt;td&gt;AWS API error, Pod Identity&lt;/td&gt;
&lt;td&gt;Correct least-privilege IAM policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10 — Scheduling Pending&lt;/td&gt;
&lt;td&gt;Taint without toleration&lt;/td&gt;
&lt;td&gt;Scheduler events&lt;/td&gt;
&lt;td&gt;Correct scheduling constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11 — Affinity failure&lt;/td&gt;
&lt;td&gt;Required placement unavailable&lt;/td&gt;
&lt;td&gt;Node labels, affinity, events&lt;/td&gt;
&lt;td&gt;Restore eligible placement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12 — Argo CD OutOfSync&lt;/td&gt;
&lt;td&gt;Manual resource change&lt;/td&gt;
&lt;td&gt;Argo CD diff and history&lt;/td&gt;
&lt;td&gt;Reconcile from Git&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13 — ALB 503&lt;/td&gt;
&lt;td&gt;No healthy application targets&lt;/td&gt;
&lt;td&gt;Target health, Ingress, endpoints&lt;/td&gt;
&lt;td&gt;Restore healthy targets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14 — DNS failure&lt;/td&gt;
&lt;td&gt;DNS resolution problem&lt;/td&gt;
&lt;td&gt;CoreDNS, Service DNS&lt;/td&gt;
&lt;td&gt;Correct DNS issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15 — Database recovery&lt;/td&gt;
&lt;td&gt;Controlled database restart&lt;/td&gt;
&lt;td&gt;StatefulSet, PVC, logs&lt;/td&gt;
&lt;td&gt;Restore database and validate data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16 — PDB and node drain&lt;/td&gt;
&lt;td&gt;Drain constrained by PDB&lt;/td&gt;
&lt;td&gt;Eviction events, PDB&lt;/td&gt;
&lt;td&gt;Safely adjust capacity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17 — RollingUpdate&lt;/td&gt;
&lt;td&gt;New release fails readiness&lt;/td&gt;
&lt;td&gt;ReplicaSets, rollout status&lt;/td&gt;
&lt;td&gt;Revert GitOps release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18 — Secret failure&lt;/td&gt;
&lt;td&gt;Missing Secret key&lt;/td&gt;
&lt;td&gt;Pod events, environment refs&lt;/td&gt;
&lt;td&gt;Restore Secret&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;19 — Resource limits&lt;/td&gt;
&lt;td&gt;Memory exhaustion&lt;/td&gt;
&lt;td&gt;OOMKilled, memory metrics&lt;/td&gt;
&lt;td&gt;Correct memory sizing/leak&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20 — CronJob failure&lt;/td&gt;
&lt;td&gt;Backup job fails&lt;/td&gt;
&lt;td&gt;Job logs, events, permissions&lt;/td&gt;
&lt;td&gt;Repair and rerun backup&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the CronJob exercise, students must verify that the backup is recoverable by restoring into a separate database. A successful backup command alone does not prove recoverability.&lt;/p&gt;
&lt;h2&gt;
  
  
  13. Phase 10 — Kubernetes controllers: what to demonstrate
&lt;/h2&gt;

&lt;p&gt;Students should understand the controller's responsibility and why the workload needs it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Controller / resource&lt;/th&gt;
&lt;th&gt;EstateFlow use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Frontend and API stateless workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ReplicaSet&lt;/td&gt;
&lt;td&gt;Maintains desired Pods through Deployment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;StatefulSet&lt;/td&gt;
&lt;td&gt;PostgreSQL and Redis lab workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DaemonSet&lt;/td&gt;
&lt;td&gt;VPC CNI, node monitoring, log agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;One-time database migration or verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CronJob&lt;/td&gt;
&lt;td&gt;Scheduled backup and maintenance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HPA&lt;/td&gt;
&lt;td&gt;Scale API replicas using resource metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ingress controller&lt;/td&gt;
&lt;td&gt;Reconcile ALB routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EBS CSI controller&lt;/td&gt;
&lt;td&gt;Provision and attach persistent volumes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Argo CD controller&lt;/td&gt;
&lt;td&gt;Reconcile desired state from Git&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node controller&lt;/td&gt;
&lt;td&gt;Detect node health changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EndpointSlice controller&lt;/td&gt;
&lt;td&gt;Maintain Service endpoint information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduler&lt;/td&gt;
&lt;td&gt;Select eligible nodes for unscheduled Pods&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Also demonstrate ServiceAccounts, Roles, RoleBindings, ClusterRoles, ClusterRoleBindings, ResourceQuotas, LimitRanges, PriorityClasses, Pod Security Admission, PodDisruptionBudgets, topology spread, and storage reclamation policies.&lt;/p&gt;

&lt;p&gt;Not every resource should be used in the same application workload. For example, a ClusterRole should not replace a namespaced Role when only namespace-scoped permissions are required.&lt;/p&gt;
&lt;h2&gt;
  
  
  14. Phase 11 — Production-readiness requirements
&lt;/h2&gt;

&lt;p&gt;Before students present EstateFlow as a production-style platform, complete the following checklist.&lt;/p&gt;

&lt;p&gt;Project readiness&lt;/p&gt;

&lt;p&gt;0 / 10 completed&lt;/p&gt;

&lt;p&gt;Application&lt;/p&gt;

&lt;p&gt;Automated backend tests, frontend build, input validation, dependency checks&lt;/p&gt;

&lt;p&gt;Container security&lt;/p&gt;

&lt;p&gt;Non-root runtime, image scanning, immutable tags, reviewed base images&lt;/p&gt;

&lt;p&gt;AWS infrastructure&lt;/p&gt;

&lt;p&gt;Terraform remote state, IAM least privilege, restricted cluster access&lt;/p&gt;

&lt;p&gt;Networking&lt;/p&gt;

&lt;p&gt;ALB controller, HTTPS, DNS, security groups, verified NetworkPolicy&lt;/p&gt;

&lt;p&gt;Kubernetes&lt;/p&gt;

&lt;p&gt;Requests/limits, probes, HPA, PDB, placement, safe rolling updates&lt;/p&gt;

&lt;p&gt;Storage&lt;/p&gt;

&lt;p&gt;EBS CSI IAM, encryption, backup, restore test, storage retention&lt;/p&gt;

&lt;p&gt;GitOps&lt;/p&gt;

&lt;p&gt;Separate GitOps repository, environment values, Argo CD project restrictions&lt;/p&gt;

&lt;p&gt;Monitoring&lt;/p&gt;

&lt;p&gt;Metrics, dashboards, alert routing, synthetic business transactions&lt;/p&gt;

&lt;p&gt;Incident response&lt;/p&gt;

&lt;p&gt;On-call roles, escalation, rollback, recovery validation, postmortem&lt;/p&gt;

&lt;p&gt;Cost and cleanup&lt;/p&gt;

&lt;p&gt;Budget alerts, resource inventory, cleanup approval and verification&lt;/p&gt;

&lt;p&gt;This checklist is a teaching gate, not a certification that the system meets a particular organization's production standards.&lt;/p&gt;
&lt;h2&gt;
  
  
  15. Phase 12 — Interview preparation
&lt;/h2&gt;

&lt;p&gt;Students should learn to describe the incident using the STAR method: Situation, Task, Action, Result.&lt;/p&gt;
&lt;h1&gt;
  
  
  DevOps/SRE Interview — EstateFlow Incident
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Question: Tell me about a Kubernetes production incident you investigated.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;During my DevOps/SRE capstone, I worked on EstateFlow, a production-style real-estate application deployed on AWS EKS.&lt;/p&gt;

&lt;p&gt;The platform used React for the frontend, Node.js for the backend, PostgreSQL for persistent data, and Redis for caching. We used Terraform for AWS infrastructure, GitHub Actions for CI, Amazon ECR for container images, and Helm with Argo CD for GitOps deployments.&lt;/p&gt;

&lt;p&gt;One of the incidents I investigated involved HTTP 503 errors on the booking API.&lt;/p&gt;

&lt;p&gt;The interesting part was that Kubernetes reported the application Pods as Running and Ready, but customers in our synthetic test could not complete booking requests.&lt;/p&gt;

&lt;p&gt;I first checked the Deployment, Pods, Services, and EndpointSlices using kubectl. Then I reviewed the application logs and tested the health and database endpoints separately.&lt;/p&gt;

&lt;p&gt;The readiness endpoint returned HTTP 200, but the database check returned HTTP 503.&lt;/p&gt;

&lt;p&gt;That told me the application process was running, but a downstream dependency was unavailable.&lt;/p&gt;

&lt;p&gt;I checked PostgreSQL health and the active Kubernetes NetworkPolicies. We found that a policy was blocking new ingress connections to the PostgreSQL Pod.&lt;/p&gt;

&lt;p&gt;I coordinated the investigation using the roles of on-call SRE, backend engineer, platform engineer, and security engineer.&lt;/p&gt;

&lt;p&gt;We restored the intended least-privilege NetworkPolicy and tested the application again.&lt;/p&gt;

&lt;p&gt;After the fix, the database endpoint returned HTTP 200 and the booking endpoint successfully created a booking with HTTP 201.&lt;/p&gt;

&lt;p&gt;We also checked the monitoring dashboards and documented the incident timeline, root cause, and preventive actions.&lt;/p&gt;

&lt;p&gt;The main lesson was that healthy Kubernetes Pods do not necessarily mean healthy business transactions. Application-level monitoring and dependency checks are essential.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If asked whether this occurred at a real employer:&lt;/strong&gt; This was a hands-on production-style lab incident that I reproduced, investigated, and recovered in AWS EKS. It was not a customer outage at a bank.&lt;/p&gt;
&lt;h3&gt;
  
  
  Follow-up questions students must answer
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Why were the Pods Running while the API returned HTTP 503?&lt;/li&gt;
&lt;li&gt;What is the difference between a readiness probe and a liveness probe?&lt;/li&gt;
&lt;li&gt;How does a NetworkPolicy select Pods?&lt;/li&gt;
&lt;li&gt;How does AWS VPC CNI enforce network isolation?&lt;/li&gt;
&lt;li&gt;Why would rolling back the API Deployment not necessarily fix a NetworkPolicy issue?&lt;/li&gt;
&lt;li&gt;How does an ALB find healthy Kubernetes targets?&lt;/li&gt;
&lt;li&gt;What is the difference between IAM and Kubernetes RBAC?&lt;/li&gt;
&lt;li&gt;Why use a StatefulSet for PostgreSQL?&lt;/li&gt;
&lt;li&gt;What happens if a PVC remains Pending?&lt;/li&gt;
&lt;li&gt;How does Argo CD detect configuration drift?&lt;/li&gt;
&lt;li&gt;What is the difference between &lt;code&gt;maxSurge&lt;/code&gt; and &lt;code&gt;maxUnavailable&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Why does an HPA need Metrics Server for CPU-based scaling?&lt;/li&gt;
&lt;li&gt;How do taints and tolerations differ from node affinity?&lt;/li&gt;
&lt;li&gt;What does a PodDisruptionBudget protect against?&lt;/li&gt;
&lt;li&gt;How do you prove a business service has recovered?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every student should answer with a command they used, an output they observed, and an explanation of what that output meant.&lt;/p&gt;
&lt;h2&gt;
  
  
  16. Phase 13 — Final project demonstration
&lt;/h2&gt;

&lt;p&gt;Each student must demonstrate:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Application: Open EstateFlow, list properties, and create a booking.&lt;/li&gt;
&lt;li&gt;AWS: Show Terraform configuration, EKS nodes, and ECR repositories.&lt;/li&gt;
&lt;li&gt;CI/CD: Show a GitHub Actions run, image publishing, and Argo CD deployment.&lt;/li&gt;
&lt;li&gt;Kubernetes: Explain Deployments, StatefulSets, Services, Ingress, HPA, PDB, and scheduling.&lt;/li&gt;
&lt;li&gt;Security: Demonstrate RBAC authorization and PostgreSQL NetworkPolicy isolation.&lt;/li&gt;
&lt;li&gt;Monitoring: Show Grafana metrics and an alert.&lt;/li&gt;
&lt;li&gt;Incident: Reproduce HTTP 503, identify the cause, restore connectivity, and verify a booking.&lt;/li&gt;
&lt;li&gt;Documentation: Submit a postmortem with actual timestamps and screenshots.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  17. Phase 14 — Safe cleanup
&lt;/h2&gt;

&lt;p&gt;Cleanup is a separate, instructor-approved activity. It must never be an unrestricted &lt;code&gt;kubectl delete --all&lt;/code&gt; or &lt;code&gt;terraform destroy&lt;/code&gt; against an unverified environment.&lt;/p&gt;

&lt;p&gt;Before cleanup, students must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Export their incident evidence and final reports.&lt;/li&gt;
&lt;li&gt;Verify the active AWS account and Kubernetes context.&lt;/li&gt;
&lt;li&gt;Confirm that all resources belong to their dedicated EstateFlow project.&lt;/li&gt;
&lt;li&gt;Back up any data they need to retain.&lt;/li&gt;
&lt;li&gt;Identify ALBs, EBS volumes, ECR images, and other resources that might remain billable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then remove the EstateFlow GitOps Applications through their approved process, allow AWS controllers to clean up managed load balancers, and verify no resources are stranded.&lt;/p&gt;

&lt;p&gt;Only after confirming Terraform manages the intended dedicated infrastructure should the student run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;terraform

terraform plan &lt;span class="nt"&gt;-destroy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review the entire destroy plan with the instructor.&lt;/p&gt;

&lt;p&gt;For a dedicated, disposable EstateFlow cluster only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;terraform&lt;/span&gt; &lt;span class="nx"&gt;destroy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never run this against infrastructure that hosts &lt;code&gt;payments-incident-lab&lt;/code&gt; or another student's resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  18. Instructor implementation notes — important gaps to finish
&lt;/h2&gt;

&lt;p&gt;The material above is a complete curriculum and implementation blueprint, with runnable examples for the core application and main incident. It is not yet a fully assembled, tested, one-command deployment repository. I want to distinguish that clearly before students copy it into their environments.&lt;/p&gt;

&lt;p&gt;These remaining implementation tasks require actual files and validation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;What still needs to be completed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Kubernetes-specific NGINX configuration and final Helm template&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;StatefulSet, Service, PVC, authentication and configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Schema migration Job, backup CronJob, restore procedure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terraform&lt;/td&gt;
&lt;td&gt;EBS CSI IAM, ALB Controller IAM, Pod Identity, GitHub OIDC, remote state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS ALB&lt;/td&gt;
&lt;td&gt;Controller installation, HTTPS, DNS, security groups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;td&gt;Complete ECR publishing workflow, SonarQube job, GitOps PR automation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Helm&lt;/td&gt;
&lt;td&gt;Full rendered templates for every application resource&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Argo CD&lt;/td&gt;
&lt;td&gt;Tested repository paths, AppProject, environment promotion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;Pod Security Admission, external secrets, complete policy tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring&lt;/td&gt;
&lt;td&gt;Tested ServiceMonitor selection, alert rules, PagerDuty routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incidents&lt;/td&gt;
&lt;td&gt;Executable injection and recovery scripts for all 20 scenarios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validation&lt;/td&gt;
&lt;td&gt;Integration tests, failure recovery, capacity and cost checks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Those gaps matter. Students should not be told that copying this document alone creates a complete production environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recommended classroom sequence
&lt;/h3&gt;

&lt;p&gt;Week 1&lt;/p&gt;

&lt;p&gt;Application, PostgreSQL, Redis, Docker Compose&lt;/p&gt;

&lt;p&gt;Week 2&lt;/p&gt;

&lt;p&gt;Terraform, VPC, EKS, IAM, ECR&lt;/p&gt;

&lt;p&gt;Week 3&lt;/p&gt;

&lt;p&gt;Kubernetes Deployments, StatefulSets, storage, Services&lt;/p&gt;

&lt;p&gt;Week 4&lt;/p&gt;

&lt;p&gt;ALB, Ingress, DNS, RBAC, NetworkPolicy, scheduling&lt;/p&gt;

&lt;p&gt;Week 5&lt;/p&gt;

&lt;p&gt;GitHub Actions, SonarQube, Trivy, Helm, Argo CD&lt;/p&gt;

&lt;p&gt;Week 6&lt;/p&gt;

&lt;p&gt;Prometheus, Grafana, PagerDuty, incident labs&lt;/p&gt;

&lt;p&gt;Week 7&lt;/p&gt;

&lt;p&gt;Incident simulation, postmortems, interview presentations&lt;/p&gt;

&lt;p&gt;My recommendation for JumpToTech: Use this as the master student syllabus and architecture guide, but keep implementation in a real GitHub repository with tested source files. Students should build and verify each phase before moving on, rather than paste a large unvalidated script into AWS.&lt;/p&gt;

&lt;p&gt;The final standard is straightforward: every student must be able to show the working application, demonstrate the failure, explain why it happened, restore service, and prove recovery using real evidence.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>interview real time questions and answers</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Thu, 05 Nov 2026 19:04:23 +0000</pubDate>
      <link>https://dev.to/jumptotech/interview-real-time-questions-and-answers-g0k</link>
      <guid>https://dev.to/jumptotech/interview-real-time-questions-and-answers-g0k</guid>
      <description>&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Tell me about yourself.&lt;br&gt;
I am DevOps Engineer with more than 5 years experience. I started at Southwest Airlines as Cloud Engineer, and after one year I got promoted to DevOps Engineer. Since September 2023 I work at Capital One. Mostly I work with AWS, Kubernetes, Terraform and GitLab CI/CD. I also used Azure, and monitoring tools like Prometheus, Grafana and Datadog. I support production, do on-call, and work on reliability, security and cost. I like to automate manual work and help developers ship apps safely.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why BigTime?&lt;br&gt;
You are building AI-powered platform, and I think AI brings many good opportunities for DevOps. Your stack is AWS, Kubernetes, Terraform and GitLab, and this is what I work with every day. I also like that engineers get ownership and solve problems independently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is your day to day?&lt;br&gt;
In the morning I check alerts and dashboards in Datadog and Grafana. Then standup. Most of the day I work on Terraform, GitLab pipelines and deployments to EKS with Helm. I help developers when deployments fail. I do patching, upgrades, cost and security work. When I am on-call, I handle incidents. I update documentation in Confluence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tell me about a hard production incident.&lt;br&gt;
After a release we had 60 replicas in 3 Availability Zones, and HTTP 500 errors went up to 18 percent. I was the on-call engineer. I checked dashboards, logs, Kubernetes deployment status and the deployment history. The errors started with the release, so we rolled back to the last stable version. I checked that pods were healthy and the error rate went down. Root cause was wrong database connection setting in the new version. After this I added canary deployments, smoke tests in the pipeline, automatic rollback on high error rate, and wrote a postmortem and runbook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do you replace long-lived credentials?&lt;br&gt;
I move secrets to Vault or AWS Secrets Manager with automatic rotation. Apps on EKS use IAM roles for service accounts, so pods get short-lived credentials. GitLab pipelines use OIDC to assume IAM roles, no static AWS keys. EC2 and Windows servers use instance roles. For RDS, passwords are in Secrets Manager with rotation. This helps with SOC 2 audits too.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Windows EC2 in production, you cannot RDP, and you cannot restart. What do you do?&lt;br&gt;
First I check if the app still works for users, maybe only RDP is broken. I check status checks, security group port 3389, NACL, route table, and the Route 53 record. Then I use SSM Session Manager or Run Command with PowerShell. I check if the RDP service is running and restart only this service, check Windows firewall, CPU, memory and disk space. I look at the console screenshot, system log and CloudWatch metrics. If restart is really needed, I take a snapshot, move traffic to other instances behind the load balancer, talk to the team, and do it in a maintenance window.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How did you save $160K?&lt;br&gt;
I added cost allocation tags so we see who spends what. I rightsized big EC2 instances, turned off dev and test at night and weekends, cleaned unused EBS volumes, snapshots and load balancers. S3 lifecycle policies to cheaper storage. Better EKS node sizing and autoscaling. Savings Plans and Reserved Instances for stable workloads. Budgets and alerts in Cost Explorer and CloudWatch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How did you reduce MTTD by 25 percent?&lt;br&gt;
I made better dashboards in Grafana and Datadog for each service. Alerts based on real symptoms like error rate, latency and pod restarts. I removed noisy alerts so the team trusts them. I added health checks and synthetic monitoring. Alerts go to PagerDuty and Slack with runbook links.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Biggest issue you fixed with Grafana?&lt;br&gt;
Booking service on EKS was slow every few days. I made a dashboard with memory, restarts and latency together. Memory went up slowly, then pods got OOMKilled and latency jumped. It was a memory leak and low memory limits. Developers fixed the leak, I fixed requests and limits and added alerts for memory growth and restarts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What are the RDS replication types?&lt;br&gt;
Multi-AZ is synchronous replication to a standby in another Availability Zone, for high availability and automatic failover, you cannot read from it. Read Replicas are asynchronous, for scaling reads and reporting, can be cross-region, and can be promoted for disaster recovery. SQL Server Multi-AZ uses Always On or mirroring.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RDS vs Aurora?&lt;br&gt;
Standard RDS is managed database with its own EBS storage per instance. Aurora is AWS cloud database for MySQL and PostgreSQL. Storage is shared and separate from compute, data copied 6 times across 3 Availability Zones, storage grows automatically. Up to 15 replicas with very low lag, failover under 30 seconds. Aurora is faster but more expensive. Aurora does not support SQL Server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitLab pipeline with two different AWS roles, how do you configure?&lt;br&gt;
I use GitLab OIDC. The job gets an ID token and assumes IAM role. Role one is read-only for terraform plan, runs on merge requests. Role two has write permissions for apply and deploy, and the trust policy allows only main branch, protected branch and production environment. Stages are validate, plan, apply, deploy. Apply is manual approval with the saved plan. Deploy updates kubeconfig and runs helm upgrade. In EKS I map the role to RBAC with access entries, so it deploys only to its namespaces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What happens when you type bigtime.net in browser?&lt;br&gt;
DNS finds the IP with UDP port 53, through the resolver to Route 53. Then TCP three-way handshake, SYN, SYN-ACK, ACK. Then TLS handshake on port 443, server sends certificate and they agree on keys. Then HTTP GET request. Traffic goes through CloudFront or load balancer, then to EC2 or EKS, and the app talks to RDS. Response comes back and browser shows the page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do you make sure the app uses S3 securely, encryption in transit?&lt;br&gt;
Bucket policy denies requests when aws:SecureTransport is false, so only HTTPS. I can require TLS 1.2 with s3:TlsVersion. App uses IAM role, least privilege, no keys. VPC gateway endpoint so traffic stays private, and bucket policy limited to this endpoint. Block Public Access on. Check with CloudTrail and AWS Config rule s3-bucket-ssl-requests-only.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some S3 objects are not encrypted with your KMS key, why and how to fix?&lt;br&gt;
Default encryption works only for new objects, so old objects keep old encryption. Also if the client sends its own encryption header, it overrides the default. I find them with S3 Inventory. I re-encrypt with S3 Batch Operations copy in place. To prevent, bucket policy denies PutObject if encryption is not aws:kms or the key ID is not my key ARN. KMS key policy allows only the right roles. AWS Config for monitoring.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Same Terraform module in dev and prod, you add an IP range, dev plan is clean, prod plan wants to destroy route table associations. Why?&lt;br&gt;
The module uses count with a list. Terraform tracks resources by index. In prod the list is longer or in different order, so new item shifts indexes and Terraform wants to destroy and recreate. Fix is for_each with stable keys like the IP range. Use moved blocks or terraform state mv to move existing resources without destroy. Add prevent_destroy on critical resources, and require approval in the pipeline if prod plan shows destroy. Also check drift with plan -refresh-only and provider versions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kubernetes app gets 502 for about 10 seconds during every deployment. Readiness probe is present. What do you check?&lt;br&gt;
Most likely old pods shutting down. Kubernetes sends SIGTERM and removes the pod at the same time, but the load balancer still sends traffic for few seconds. Fix is preStop hook with sleep 10 to 15 seconds, app handles SIGTERM gracefully, terminationGracePeriodSeconds longer than the sleep. Rolling update with maxUnavailable 0 and maxSurge 1. With ALB, enable pod readiness gates and check deregistration delay and keep-alive timeout. Add PodDisruptionBudget. Check ALB logs and pod events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do you use AI in your work?&lt;br&gt;
I use chat for quick questions and errors. For bigger tasks I use AI agents like Claude Code. It reads the repo, makes a plan, changes Terraform or pipelines, and runs terraform plan or tests. I review the plan and the changes before merge. Agents use tools through MCP and need limited permissions, like read-only in prod and no apply without human approval. I never put secrets or customer data into AI tools.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next round they may also ask these, because they are in the job description:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;How do you deploy and monitor .NET apps?&lt;br&gt;
I build the app in GitLab CI with dotnet build and dotnet test, then package it. For Windows on EC2, I deploy with PowerShell scripts or SSM Run Command to IIS, and take the server out of the load balancer during deploy. For Linux, I put .NET Core in Docker and deploy to EKS or ECS with Helm. For monitoring I use CloudWatch agent for Windows logs and IIS logs, and Datadog APM or OpenTelemetry for traces, errors and response time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do you patch Windows and Linux servers?&lt;br&gt;
I use AWS Systems Manager Patch Manager with patch baselines and maintenance windows. First patch dev and test, then prod. For prod, I patch in groups, so not all servers behind the load balancer go down at once. Before patching I take snapshots. After patching I check the app health and the compliance report in SSM. For EKS nodes I update the AMI and do rolling node replacement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EKS vs ECS vs App Runner?&lt;br&gt;
EKS is Kubernetes, more control and flexible, good for complex apps, but more work to manage. ECS is AWS own container service, simpler, works well with Fargate and other AWS services. App Runner is the simplest, you give it image or code, and AWS handles everything, good for small web apps and APIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is Helmfile?&lt;br&gt;
Helmfile manages many Helm releases in one file. You define all charts, versions and values for each environment in one place, and run helmfile apply. It is good for keeping environments consistent and works well in CI/CD.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is Terragrunt and why use it?&lt;br&gt;
Terragrunt is a wrapper for Terraform. It keeps the code DRY, so you don't copy the same backend and provider config in every environment. It manages remote state config, dependencies between modules, and lets you run plan or apply across many modules and accounts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do you help with SOC 2?&lt;br&gt;
I make sure access is least privilege with IAM roles and SSO, encryption at rest with KMS and in transit with TLS, logs in CloudTrail and CloudWatch, vulnerability scanning with Inspector or image scanning in the pipeline, and patching. I keep evidence and documentation ready for auditors, like access reviews and change history from GitLab merge requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is your disaster recovery approach?&lt;br&gt;
First we agree on RTO and RPO with the business. Backups for RDS with automated snapshots and cross-region copies, S3 versioning and replication, all infrastructure in Terraform so we can rebuild fast. We write a DR runbook and test it, because a plan that is not tested does not work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have you worked with Lambda?&lt;br&gt;
Yes, I used Lambda for automation, like stopping dev instances at night, cleaning old snapshots, and processing S3 events. I deploy it with Terraform, give it a small IAM role, and monitor with CloudWatch logs and alarms for errors and duration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is Ansible used for?&lt;br&gt;
Configuration management. It connects to servers over SSH for Linux or WinRM for Windows, and runs playbooks to install software, change config and patch. It is agentless and idempotent, so you can run it many times and it gives the same result.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Biggest weakness?&lt;br&gt;
Sometimes I go too deep into a problem and want to fix it myself. Now I set a time limit, and if I don't solve it, I ask the team early.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Where do you see yourself in 3 to 5 years?&lt;br&gt;
I want to grow into Senior or Lead DevOps Engineer, own bigger parts of the platform, and help build automation and AI tools for the team.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>career</category>
      <category>devops</category>
      <category>interview</category>
    </item>
    <item>
      <title>JumpToTech DevOps Bootcamp Real Estate Company — Complete AWS EKS Integration Lab</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Thu, 05 Nov 2026 17:45:05 +0000</pubDate>
      <link>https://dev.to/jumptotech/jumptotech-devops-bootcamp-real-estate-company-complete-aws-eks-integration-lab-19h9</link>
      <guid>https://dev.to/jumptotech/jumptotech-devops-bootcamp-real-estate-company-complete-aws-eks-integration-lab-19h9</guid>
      <description>&lt;h2&gt;
  
  
  1. What you will build
&lt;/h2&gt;

&lt;p&gt;Customer / Browser&lt;/p&gt;

&lt;p&gt;View properties, submit inquiries&lt;/p&gt;

&lt;p&gt;AWS Application Load Balancer&lt;/p&gt;

&lt;p&gt;Kubernetes Ingress managed by AWS Load Balancer Controller&lt;/p&gt;

&lt;p&gt;Frontend Deployment&lt;/p&gt;

&lt;p&gt;Nginx + React&lt;/p&gt;

&lt;p&gt;frontend-service&lt;/p&gt;

&lt;p&gt;Backend Deployment&lt;/p&gt;

&lt;p&gt;FastAPI + SQL&lt;/p&gt;

&lt;p&gt;backend-service&lt;/p&gt;

&lt;p&gt;Amazon RDS PostgreSQL&lt;/p&gt;

&lt;p&gt;Main application database — outside Kubernetes&lt;/p&gt;

&lt;p&gt;Separate PostgreSQL StatefulSet&lt;/p&gt;

&lt;p&gt;PVC → PV → AWS EBS volume&lt;/p&gt;

&lt;p&gt;Persistence experiment only&lt;/p&gt;

&lt;p&gt;Fluent Bit DaemonSet&lt;/p&gt;

&lt;p&gt;Collects node container logs → CloudWatch Logs&lt;/p&gt;

&lt;h3&gt;
  
  
  What each component is responsible for
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend Deployment&lt;/td&gt;
&lt;td&gt;Runs website Pods and maintains desired replicas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend Deployment&lt;/td&gt;
&lt;td&gt;Runs API Pods that process property and inquiry requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ReplicaSet&lt;/td&gt;
&lt;td&gt;Maintains Pods created by a Deployment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ClusterIP Service&lt;/td&gt;
&lt;td&gt;Provides a stable internal network endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ingress / ALB&lt;/td&gt;
&lt;td&gt;Routes incoming HTTP traffic to Services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon RDS&lt;/td&gt;
&lt;td&gt;Manages PostgreSQL database infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;StatefulSet&lt;/td&gt;
&lt;td&gt;Maintains stable Pod identities for our separate database experiment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PVC / PV&lt;/td&gt;
&lt;td&gt;Connects the StatefulSet to persistent storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;StorageClass&lt;/td&gt;
&lt;td&gt;Defines how storage is dynamically provisioned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EBS CSI Driver&lt;/td&gt;
&lt;td&gt;Integrates Kubernetes storage operations with AWS EBS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DaemonSet&lt;/td&gt;
&lt;td&gt;Ensures a log collection agent runs on eligible nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kubelet&lt;/td&gt;
&lt;td&gt;Starts and monitors Pod containers on a worker node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IAM&lt;/td&gt;
&lt;td&gt;Controls AWS permissions for controllers and workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes Secret&lt;/td&gt;
&lt;td&gt;Provides application credentials to Pods&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Important: We will not place RDS inside a StatefulSet. These are two separate database deployment models.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Lab phases
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Activity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Inspect existing repository and EKS cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Verify frontend/backend application and Docker images&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Deploy frontend/backend using Deployments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Create internal ClusterIP Services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Configure ALB Ingress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Provision and connect Amazon RDS PostgreSQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Deploy separate PostgreSQL StatefulSet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Configure EBS CSI, StorageClass and PVC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Deploy Fluent Bit DaemonSet with CloudWatch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Test, troubleshoot, document and clean up&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is a multi-session project, not a 30-minute exercise. Complete one phase successfully before proceeding.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Phase 1 — Inspect the existing project
&lt;/h2&gt;

&lt;p&gt;Why: A DevOps Engineer should understand the existing infrastructure and application before modifying it.&lt;/p&gt;

&lt;p&gt;On the EC2 instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/real-estate-company

&lt;span class="nb"&gt;pwd
&lt;/span&gt;git status &lt;span class="nt"&gt;--short&lt;/span&gt;
git remote &lt;span class="nt"&gt;-v&lt;/span&gt;

&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; backend
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; frontend
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; k8s

find backend frontend k8s &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 2 &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect Docker and Kubernetes files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; Dockerfile &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.yaml'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.yml'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the AWS identity and cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws sts get-caller-identity
aws configure get region
kubectl config current-context
kubectl get nodes &lt;span class="nt"&gt;-o&lt;/span&gt; wide
kubectl get namespaces
kubectl get deployments,services,ingresses &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Student checkpoint: Identify the frontend technology, backend technology, existing container ports, current Kubernetes namespace, ECR repositories and EKS cluster name.&lt;/p&gt;

&lt;p&gt;Do not print &lt;code&gt;.env&lt;/code&gt; files, passwords, tokens or database connection strings into shared classroom screenshots.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Phase 2 — Prepare the application
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What the application must do
&lt;/h3&gt;

&lt;p&gt;Your Real Estate Company will have two parts.&lt;/p&gt;

&lt;p&gt;Frontend: Display available properties, prices, locations and an inquiry form.&lt;/p&gt;

&lt;p&gt;Backend: Return property listings, receive customer inquiries, validate requests and save them in PostgreSQL.&lt;/p&gt;

&lt;p&gt;The backend is responsible for SQL operations. Kubernetes is responsible for running and connecting the application, not for implementing its business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 Reference backend — FastAPI
&lt;/h3&gt;

&lt;p&gt;If your existing backend already implements these features, retain it and adapt the Kubernetes configuration. Otherwise, create this reference backend in a separate directory so that you do not overwrite your classmates' work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/real-estate-company
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; lab-reference/backend
&lt;span class="nb"&gt;cd &lt;/span&gt;lab-reference/backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;requirements.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fastapi==0.115.12
uvicorn==0.34.2
psycopg[binary]==3.2.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;main.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;osfrom&lt;/span&gt; &lt;span class="n"&gt;contextlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asynccontextmanagerimport&lt;/span&gt; &lt;span class="n"&gt;psycopgfrom&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTTPExceptionfrom&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FieldDATABASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;psycopg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connect_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;@asynccontextmanagerasync&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lifespan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;            CREATE TABLE IF NOT EXISTS properties (                id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,                title TEXT NOT NULL,                city TEXT NOT NULL,                price INTEGER NOT NULL            )        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;            CREATE TABLE IF NOT EXISTS inquiries (                id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,                property_id INTEGER NOT NULL REFERENCES properties(id),                customer_name TEXT NOT NULL,                email TEXT NOT NULL,                message TEXT NOT NULL,                created_at TIMESTAMPTZ NOT NULL DEFAULT now()            )        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is teaching code, not a production-ready customer-data platform. It omits authentication, authorization, rate limiting, full email validation and a proper migration workflow. Use fictitious customer information only.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.12-slim&lt;/span&gt;

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

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; main.py .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;--uid&lt;/span&gt; 10001 &lt;span class="nt"&gt;--create-home&lt;/span&gt; appuser
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; 10001&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8000&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why Docker? Kubernetes deploys container images. It does not directly deploy your Python source folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Reference frontend — React
&lt;/h3&gt;

&lt;p&gt;For students who already have a working React frontend, retain the existing code and adapt its API calls to &lt;code&gt;/api/properties&lt;/code&gt; and &lt;code&gt;/api/inquiries&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For a new reference frontend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/real-estate-company/lab-reference
npm create vite@latest frontend &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; react
&lt;span class="nb"&gt;cd &lt;/span&gt;frontend
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;src/App.jsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProperties&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setResult&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/properties&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API unavailable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;setSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unable to load properties&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/inquiries&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;property_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="na"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;message&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Request failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;setResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Inquiry saved! Reference #&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unable to save inquiry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;40px auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontFamily&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Arial&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;JumpToTech Real Estate&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Explore properties and request more information.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;$&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Contact an agent&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Your name"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Email"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Your question"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Send inquiry&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;nginx.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/usr/share/nginx/html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="n"&gt;/index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:22-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginxinc/nginx-unprivileged:stable-alpine&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; nginx.conf /etc/nginx/conf.d/default.conf&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/dist /usr/share/nginx/html&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why use &lt;code&gt;/api&lt;/code&gt;? The browser can access the frontend and backend through the same ALB hostname. The Ingress sends &lt;code&gt;/api/*&lt;/code&gt; requests to the backend, avoiding the need for browser-side access to a private ClusterIP.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Phase 3 — Build images and push to Amazon ECR
&lt;/h2&gt;

&lt;p&gt;First define your AWS environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_ACCOUNT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws sts get-caller-identity &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; Account &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EKS_CLUSTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_EKS_CLUSTER"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"real-estate-lab"&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FRONTEND_REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"real-estate-frontend"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BACKEND_REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"real-estate-backend"&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;IMAGE_TAG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"lab-v1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;YOUR_EKS_CLUSTER&lt;/code&gt; with the actual cluster name.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create ECR repositories
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecr describe-repositories &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repository-names&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FRONTEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;||&lt;/span&gt;
aws ecr create-repository &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repository-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FRONTEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repeat for the backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecr describe-repositories &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repository-names&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;||&lt;/span&gt;
aws ecr create-repository &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repository-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authenticate Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecr get-login-password &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; |
docker login &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--username&lt;/span&gt; AWS &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--password-stdin&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_ACCOUNT_ID&lt;/span&gt;&lt;span class="s2"&gt;.dkr.ecr.&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;.amazonaws.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build and push from the reference implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/real-estate-company/lab-reference

docker build &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE_TAG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; ./backend

docker tag &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE_TAG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_ACCOUNT_ID&lt;/span&gt;&lt;span class="s2"&gt;.dkr.ecr.&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;.amazonaws.com/&lt;/span&gt;&lt;span class="nv"&gt;$BACKEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE_TAG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

docker push &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_ACCOUNT_ID&lt;/span&gt;&lt;span class="s2"&gt;.dkr.ecr.&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;.amazonaws.com/&lt;/span&gt;&lt;span class="nv"&gt;$BACKEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE_TAG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FRONTEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE_TAG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; ./frontend

docker tag &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FRONTEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE_TAG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_ACCOUNT_ID&lt;/span&gt;&lt;span class="s2"&gt;.dkr.ecr.&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;.amazonaws.com/&lt;/span&gt;&lt;span class="nv"&gt;$FRONTEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE_TAG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

docker push &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_ACCOUNT_ID&lt;/span&gt;&lt;span class="s2"&gt;.dkr.ecr.&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;.amazonaws.com/&lt;/span&gt;&lt;span class="nv"&gt;$FRONTEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE_TAG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands assume x86-64 EKS nodes. If your EKS nodes are ARM64, use &lt;code&gt;linux/arm64&lt;/code&gt; instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecr list-images &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repository-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

aws ecr list-images &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repository-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FRONTEND_REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Student question: Why does Kubernetes need the ECR image URI rather than the source-code directory?&lt;/p&gt;

&lt;p&gt;Answer: The container runtime pulls a packaged image containing the application and its dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Phase 4 — Amazon RDS PostgreSQL
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why RDS?
&lt;/h3&gt;

&lt;p&gt;In this architecture, RDS manages the database service outside the Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;Kubernetes does not schedule or restart the RDS database process. AWS manages the database instance infrastructure, while your team remains responsible for database configuration, access control, schema, queries and appropriate backup settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Inspect networking before provisioning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws eks describe-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EKS_CLUSTER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'cluster.resourcesVpcConfig'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find the VPC ID and subnet IDs.&lt;/p&gt;

&lt;p&gt;For this lab, RDS should be in private subnets reachable from the EKS worker nodes. Do not make PostgreSQL publicly accessible.&lt;/p&gt;

&lt;p&gt;You will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A DB subnet group covering suitable subnets in at least two Availability Zones.&lt;/li&gt;
&lt;li&gt;An RDS security group.&lt;/li&gt;
&lt;li&gt;A rule allowing TCP 5432 from the EKS node security group, or another narrowly scoped security group used by the workloads.&lt;/li&gt;
&lt;li&gt;A PostgreSQL database and database user.&lt;/li&gt;
&lt;li&gt;A secure way to provide the credentials to the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6.2 Create RDS
&lt;/h3&gt;

&lt;p&gt;For a shared class, the instructor should provision RDS once. Students should not each create expensive AWS infrastructure without checking costs and quotas.&lt;/p&gt;

&lt;p&gt;In the AWS Console:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open RDS → Databases → Create database.&lt;/li&gt;
&lt;li&gt;Select PostgreSQL.&lt;/li&gt;
&lt;li&gt;Choose an appropriately small lab instance, such as &lt;code&gt;db.t4g.micro&lt;/code&gt; where supported and available.&lt;/li&gt;
&lt;li&gt;Set database name to &lt;code&gt;realestate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use RDS-managed master credentials in AWS Secrets Manager where available.&lt;/li&gt;
&lt;li&gt;Choose the same VPC as EKS.&lt;/li&gt;
&lt;li&gt;Select a private DB subnet group.&lt;/li&gt;
&lt;li&gt;Set Public access to No.&lt;/li&gt;
&lt;li&gt;Attach the restricted RDS security group.&lt;/li&gt;
&lt;li&gt;Configure backups and deletion protection according to the lab's cleanup plan.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not store the master password in Git.&lt;/p&gt;

&lt;p&gt;After RDS becomes available, record the endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;YOUR_RDS_ENDPOINT.rds.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.3 Create an application database user
&lt;/h3&gt;

&lt;p&gt;Use a database administrator connection from an approved private network location.&lt;/p&gt;

&lt;p&gt;Create a dedicated application user with the permissions required for the lab rather than using the RDS master account in the backend.&lt;/p&gt;

&lt;p&gt;For a simplified classroom environment, an instructor can provision the database and grant the application user ownership of its schema. Production systems should use separate migration and runtime roles with narrower privileges.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.4 Create the Kubernetes Secret
&lt;/h3&gt;

&lt;p&gt;The simplest teaching method is a Kubernetes Secret. In production, prefer AWS Secrets Manager with a supported integration such as the Secrets Store CSI Driver or External Secrets Operator.&lt;/p&gt;

&lt;p&gt;Create the namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NAMESPACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On your private terminal, read the application password without echoing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-rs&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"RDS application password: "&lt;/span&gt; DB_PASSWORD
&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Construct the connection string using the actual endpoint, database username and URL-encoded password. Special characters in passwords must be percent-encoded in a URI.&lt;/p&gt;

&lt;p&gt;For this lab, a simpler and safer option is to create individual Secret keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic realestate-db &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NAMESPACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;DB_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_RDS_ENDPOINT"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;DB_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"5432"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;DB_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"realestate"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;DB_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"realestate_app"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB_PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then remove the shell variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;unset &lt;/span&gt;DB_PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not paste passwords into a shared Zoom chat or commit them to Git.&lt;/p&gt;

&lt;p&gt;For the reference FastAPI application, we will use a small code change to construct the PostgreSQL connection from these environment variables instead of a single URL.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;psycopg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connect_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;psycopg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;        &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_HOST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;        &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_PORT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;        &lt;span class="n"&gt;dbname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_USER&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;        &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;        &lt;span class="n"&gt;connect_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="n"&gt;sslmode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;require&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rebuild and push the backend image with a new tag, for example &lt;code&gt;lab-v2&lt;/code&gt;, and use that tag in the Deployment below.&lt;/p&gt;

&lt;p&gt;Production note: &lt;code&gt;sslmode=require&lt;/code&gt; encrypts the connection but does not provide full server identity verification. Production should use &lt;code&gt;verify-full&lt;/code&gt; with an appropriate RDS CA bundle.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Phase 5 — Kubernetes Deployments and Services
&lt;/h2&gt;

&lt;p&gt;Create a directory for the new lab manifests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/real-estate-company
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; lab-reference/k8s
&lt;span class="nb"&gt;cd &lt;/span&gt;lab-reference/k8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.1 Backend Deployment
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;backend.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-backend&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;real-estate-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-backend&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-backend&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;BACKEND_IMAGE_URI&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
          &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-db&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;128Mi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;512Mi&lt;/span&gt;
          &lt;span class="na"&gt;startupProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/healthz&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
            &lt;span class="na"&gt;failureThreshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/readyz&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
          &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/healthz&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend-service&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;real-estate-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-backend&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;BACKEND_IMAGE_URI&lt;/code&gt; with the full ECR image URI, including its tag.&lt;/p&gt;

&lt;p&gt;Why two replicas? We want to demonstrate how a Deployment maintains multiple backend Pods and how a Service routes requests to healthy endpoints.&lt;/p&gt;

&lt;p&gt;Why separate readiness and liveness? If RDS is unavailable, readiness should fail so the Pod stops receiving traffic. Liveness should not depend on RDS, or a temporary database outage could cause unnecessary container restarts.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.2 Frontend Deployment
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;frontend.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-frontend&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;real-estate-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-frontend&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-frontend&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FRONTEND_IMAGE_URI&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;50m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;64Mi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;256Mi&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend-service&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;real-estate-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-frontend&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;FRONTEND_IMAGE_URI&lt;/code&gt; with the full ECR URI.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.3 Apply and verify
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; backend.yaml
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; frontend.yaml

kubectl rollout status deployment/realestate-backend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180s

kubectl rollout status deployment/realestate-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployments &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
kubectl get replicasets &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;-o&lt;/span&gt; wide
kubectl get services &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
kubectl get endpointslices &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected result: Two frontend Pods and two backend Pods should be Ready, provided the images can be pulled and the backend can reach RDS.&lt;/p&gt;

&lt;p&gt;If backend Pods are not Ready, investigate before moving on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pod &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;realestate-backend

kubectl logs deployment/realestate-backend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.4 Test the backend without ALB
&lt;/h3&gt;

&lt;p&gt;Use port forwarding from a machine with kubectl access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab svc/backend-service 8081:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a second terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8081/healthz
curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8081/readyz
curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8081/api/properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a sample inquiry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8081/api/inquiries &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "property_id": 1,
    "customer_name": "Test Student",
    "email": "student@example.com",
    "message": "I would like a property tour."
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8081/api/inquiries/count
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Student checkpoint: Explain the complete path from the HTTP request through Service, Backend Pod and RDS PostgreSQL.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Phase 6 — AWS ALB Ingress
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Ingress?
&lt;/h3&gt;

&lt;p&gt;Our ClusterIP Services are reachable only through Kubernetes networking. Customers need an external HTTP entry point.&lt;/p&gt;

&lt;p&gt;AWS Load Balancer Controller can create and manage an Application Load Balancer from a Kubernetes Ingress.&lt;/p&gt;

&lt;p&gt;Before proceeding, verify that the AWS Load Balancer Controller is installed, has appropriate IAM permissions and that the VPC subnets are correctly tagged for load balancer discovery.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment aws-load-balancer-controller &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system

kubectl get ingressclass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the controller is missing, do not assume that creating an Ingress will automatically provision an ALB. The instructor must first install the controller using the supported AWS installation procedure and IAM configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  8.1 Create the Ingress
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;ingress.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-ingress&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;real-estate-lab&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;alb.ingress.kubernetes.io/scheme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;internet-facing&lt;/span&gt;
    &lt;span class="na"&gt;alb.ingress.kubernetes.io/target-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ip&lt;/span&gt;
    &lt;span class="na"&gt;alb.ingress.kubernetes.io/healthcheck-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
    &lt;span class="na"&gt;alb.ingress.kubernetes.io/listen-ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[{"HTTP":80}]'&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alb&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend-service&lt;/span&gt;
                &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend-service&lt;/span&gt;
                &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; ingress.yaml
kubectl get ingress &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
kubectl describe ingress realestate-ingress &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ADDRESS&lt;/code&gt; field should eventually contain an ALB hostname if provisioning succeeds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Important production distinction
&lt;/h3&gt;

&lt;p&gt;This is an HTTP-only classroom configuration. Do not send real customer information through it. For a real application, configure HTTPS using ACM, an HTTPS listener, appropriate redirect rules and an approved DNS name.&lt;/p&gt;

&lt;p&gt;The single ALB routes &lt;code&gt;/api&lt;/code&gt; to Backend and &lt;code&gt;/&lt;/code&gt; to Frontend. The frontend uses relative &lt;code&gt;/api&lt;/code&gt; requests, so browser requests reach the same ALB hostname.&lt;/p&gt;

&lt;h3&gt;
  
  
  8.2 Verify
&lt;/h3&gt;

&lt;p&gt;Once the ALB hostname is assigned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ALB_DNS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get ingress realestate-ingress &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.loadBalancer.ingress[0].hostname}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALB_DNS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

curl &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"http://&lt;/span&gt;&lt;span class="nv"&gt;$ALB_DNS&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;
curl &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"http://&lt;/span&gt;&lt;span class="nv"&gt;$ALB_DNS&lt;/span&gt;&lt;span class="s2"&gt;/api/properties"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see &lt;code&gt;502&lt;/code&gt;, &lt;code&gt;503&lt;/code&gt; or &lt;code&gt;504&lt;/code&gt;, do not immediately restart the Pods. Inspect the ALB target groups, backend health, Service endpoints, application logs and database connectivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Phase 7 — PostgreSQL StatefulSet with EBS
&lt;/h2&gt;

&lt;p&gt;This phase is a separate experiment from the RDS database.&lt;/p&gt;

&lt;p&gt;Our main Real Estate Company uses RDS. Now we will deploy another PostgreSQL instance inside Kubernetes to understand StatefulSet, PVC, PV, StorageClass and the EBS CSI driver.&lt;/p&gt;

&lt;h3&gt;
  
  
  9.1 Understand the storage path
&lt;/h3&gt;

&lt;p&gt;StatefulSet&lt;/p&gt;

&lt;p&gt;Creates and manages postgres-0&lt;/p&gt;

&lt;p&gt;Pod&lt;/p&gt;

&lt;p&gt;Runs the PostgreSQL database software&lt;/p&gt;

&lt;p&gt;PVC&lt;/p&gt;

&lt;p&gt;Requests 5 GiB of persistent storage&lt;/p&gt;

&lt;p&gt;StorageClass&lt;/p&gt;

&lt;p&gt;Selects the EBS storage provisioner&lt;/p&gt;

&lt;p&gt;EBS CSI Driver&lt;/p&gt;

&lt;p&gt;Coordinates EBS volume provisioning and attachment&lt;/p&gt;

&lt;p&gt;PV / EBS Volume&lt;/p&gt;

&lt;p&gt;Stores PostgreSQL data files&lt;/p&gt;

&lt;h3&gt;
  
  
  9.2 Check EBS CSI and StorageClasses
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get csidrivers
kubectl get storageclass &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a standard EKS installation with the EBS CSI driver, the CSI provisioner is typically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ebs.csi.aws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For EKS Auto Mode, the provisioner is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ebs.csi.eks.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the driver and StorageClass that actually match your cluster.&lt;/p&gt;

&lt;p&gt;If EBS CSI is missing, the instructor must install the appropriate EKS add-on and configure its AWS IAM permissions. The CSI controller needs permissions to provision and manage EBS volumes. Merely creating a PVC will not grant those permissions.&lt;/p&gt;

&lt;p&gt;For standard EKS with the standard EBS CSI driver, create &lt;code&gt;storageclass.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;StorageClass&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-gp3&lt;/span&gt;
&lt;span class="na"&gt;provisioner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ebs.csi.aws.com&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gp3&lt;/span&gt;
&lt;span class="na"&gt;reclaimPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Delete&lt;/span&gt;
&lt;span class="na"&gt;volumeBindingMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WaitForFirstConsumer&lt;/span&gt;
&lt;span class="na"&gt;allowVolumeExpansion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For EKS Auto Mode, use its supported provisioner instead and review the applicable configuration before creating the class.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; storageclass.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why &lt;code&gt;WaitForFirstConsumer&lt;/code&gt;? EBS volumes are Availability Zone-specific. Kubernetes should consider the Pod's placement before provisioning the volume.&lt;/p&gt;

&lt;p&gt;Why &lt;code&gt;reclaimPolicy: Delete&lt;/code&gt;? This is a disposable classroom lab. Deleting the PVC may lead to deletion of its dynamically provisioned EBS volume. Do not use this configuration for valuable data without understanding its consequences.&lt;/p&gt;

&lt;h3&gt;
  
  
  9.3 Create the PostgreSQL credentials
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-rs&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Lab PostgreSQL password: "&lt;/span&gt; PG_PASSWORD
&lt;span class="nb"&gt;echo

&lt;/span&gt;kubectl create secret generic postgres-lab-secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;labuser &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PG_PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;labdb

&lt;span class="nb"&gt;unset &lt;/span&gt;PG_PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.4 Create PostgreSQL StatefulSet
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;postgres-statefulset.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-headless&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;real-estate-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-lab&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;StatefulSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;real-estate-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;serviceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-headless&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-lab&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-lab&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;fsGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;999&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
          &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-lab-secret&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PGDATA&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/postgresql/data/pgdata&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-data&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/postgresql/data&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;256Mi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/bin/sh&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;-c&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"&lt;/span&gt;
            &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;volumeClaimTemplates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-data&lt;/span&gt;
      &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&lt;/span&gt;
        &lt;span class="na"&gt;storageClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;realestate-gp3&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why one replica? Creating three PostgreSQL Pods does not automatically configure PostgreSQL replication. We are demonstrating persistence and stable identity, not building a highly available database cluster.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; postgres-statefulset.yaml

kubectl get statefulset &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres-lab
kubectl get pvc &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
kubectl get pv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait until &lt;code&gt;postgres-0&lt;/code&gt; is Running/Ready and the PVC is Bound.&lt;/p&gt;

&lt;h3&gt;
  
  
  9.5 Create test data
&lt;/h3&gt;

&lt;p&gt;Open PostgreSQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; postgres-0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  psql &lt;span class="nt"&gt;-U&lt;/span&gt; labuser &lt;span class="nt"&gt;-d&lt;/span&gt; labdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;psql&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;property_notes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;property_name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;note&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;property_notes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;property_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Chicago Condo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Customer requested a tour'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;property_notes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\q
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.6 Delete the PostgreSQL Pod
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod postgres-0 &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl rollout status statefulset/postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;300s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the data again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;postgres-0 &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  psql &lt;span class="nt"&gt;-U&lt;/span&gt; labuser &lt;span class="nt"&gt;-d&lt;/span&gt; labdb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM property_notes;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected: The saved record remains because PostgreSQL is using its persistent volume.&lt;/p&gt;

&lt;h3&gt;
  
  
  Student explanation
&lt;/h3&gt;

&lt;p&gt;The StatefulSet recreated &lt;code&gt;postgres-0&lt;/code&gt; with its stable identity. The PVC remained associated with the StatefulSet ordinal, and Kubernetes remounted the existing persistent storage.&lt;/p&gt;

&lt;p&gt;If the underlying EBS volume is deleted, corrupted or unavailable, StatefulSet alone cannot recover the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Phase 8 — DaemonSet and centralized logging
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is DaemonSet responsible for?
&lt;/h3&gt;

&lt;p&gt;A DaemonSet controller ensures that an eligible worker node runs a Pod for a particular node-level workload.&lt;/p&gt;

&lt;p&gt;Typical examples include log collectors, monitoring agents and some networking components.&lt;/p&gt;

&lt;p&gt;A DaemonSet does not replace kubelet, and it does not automatically centralize logs. We need a log collector and a destination.&lt;/p&gt;

&lt;p&gt;For this project:&lt;/p&gt;

&lt;p&gt;Fluent Bit DaemonSet → Amazon CloudWatch Logs&lt;/p&gt;

&lt;h3&gt;
  
  
  10.1 Understand the architecture
&lt;/h3&gt;

&lt;p&gt;Worker Node 1&lt;/p&gt;

&lt;p&gt;Application Pods&lt;/p&gt;

&lt;p&gt;Fluent Bit Pod&lt;/p&gt;

&lt;p&gt;Worker Node 2&lt;/p&gt;

&lt;p&gt;Application Pods&lt;/p&gt;

&lt;p&gt;Fluent Bit Pod&lt;/p&gt;

&lt;p&gt;Amazon CloudWatch Logs&lt;/p&gt;

&lt;p&gt;Centralized application and container logs&lt;/p&gt;

&lt;h3&gt;
  
  
  10.2 Verify IAM permissions
&lt;/h3&gt;

&lt;p&gt;The Fluent Bit workload needs permission to create log streams and publish log events.&lt;/p&gt;

&lt;p&gt;For standard EKS, prefer a dedicated IAM role for the collector using EKS Pod Identity or IRSA, according to your cluster configuration. Do not give every application Pod broad CloudWatch permissions.&lt;/p&gt;

&lt;p&gt;A minimum illustrative policy for an instructor-created CloudWatch log group is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"logs:CreateLogStream"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"logs:PutLogEvents"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"logs:DescribeLogStreams"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:logs:us-east-1:ACCOUNT_ID:log-group:/jumptotech/real-estate:*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;ACCOUNT_ID&lt;/code&gt; with the actual AWS account ID. The instructor must configure the trust relationship and attach this policy to the collector's dedicated role.&lt;/p&gt;

&lt;p&gt;Create the log group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws logs create-log-group &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--log-group-name&lt;/span&gt; /jumptotech/real-estate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the log group already exists, AWS returns an already-exists error; that does not mean logging is broken.&lt;/p&gt;

&lt;p&gt;Set a short retention period for the lab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws logs put-retention-policy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--log-group-name&lt;/span&gt; /jumptotech/real-estate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--retention-in-days&lt;/span&gt; 7 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  10.3 Install Fluent Bit with Helm
&lt;/h3&gt;

&lt;p&gt;For a real centralized-logging lab, use the maintained Fluent Bit Helm chart rather than writing an incomplete logging DaemonSet from scratch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add fluent https://fluent.github.io/helm-charts
helm repo update

helm show values fluent/fluent-bit &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; fluent-default-values.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Helm chart must be configured for your EKS runtime log paths, CloudWatch output and IAM integration. Do not assume that the default values automatically send logs to CloudWatch.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;fluent-values.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DaemonSet&lt;/span&gt;

&lt;span class="na"&gt;serviceAccount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fluent-bit-realestate&lt;/span&gt;

&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;[SERVICE]&lt;/span&gt;
        &lt;span class="s"&gt;Flush         5&lt;/span&gt;
        &lt;span class="s"&gt;Daemon        Off&lt;/span&gt;
        &lt;span class="s"&gt;Log_Level     info&lt;/span&gt;
        &lt;span class="s"&gt;Parsers_File  /fluent-bit/etc/parsers.conf&lt;/span&gt;
        &lt;span class="s"&gt;HTTP_Server   On&lt;/span&gt;
        &lt;span class="s"&gt;HTTP_Listen   0.0.0.0&lt;/span&gt;
        &lt;span class="s"&gt;HTTP_Port     2020&lt;/span&gt;

  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;[INPUT]&lt;/span&gt;
        &lt;span class="s"&gt;Name              tail&lt;/span&gt;
        &lt;span class="s"&gt;Path              /var/log/containers/*real-estate-lab*.log&lt;/span&gt;
        &lt;span class="s"&gt;Tag               kube.*&lt;/span&gt;
        &lt;span class="s"&gt;Mem_Buf_Limit     5MB&lt;/span&gt;
        &lt;span class="s"&gt;Skip_Long_Lines   On&lt;/span&gt;
        &lt;span class="s"&gt;Refresh_Interval  10&lt;/span&gt;
        &lt;span class="s"&gt;DB                /var/log/flb_realestate.db&lt;/span&gt;

  &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;[FILTER]&lt;/span&gt;
        &lt;span class="s"&gt;Name   kubernetes&lt;/span&gt;
        &lt;span class="s"&gt;Match  kube.*&lt;/span&gt;
        &lt;span class="s"&gt;Kube_Tag_Prefix kube.var.log.containers.&lt;/span&gt;
        &lt;span class="s"&gt;Merge_Log On&lt;/span&gt;
        &lt;span class="s"&gt;Keep_Log Off&lt;/span&gt;

  &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;[OUTPUT]&lt;/span&gt;
        &lt;span class="s"&gt;Name cloudwatch_logs&lt;/span&gt;
        &lt;span class="s"&gt;Match kube.*&lt;/span&gt;
        &lt;span class="s"&gt;region us-east-1&lt;/span&gt;
        &lt;span class="s"&gt;log_group_name /jumptotech/real-estate&lt;/span&gt;
        &lt;span class="s"&gt;log_stream_prefix fluentbit-&lt;/span&gt;
        &lt;span class="s"&gt;auto_create_group false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install only after the Fluent Bit ServiceAccount has been connected to the appropriate AWS IAM role. With EKS Pod Identity, this requires a Pod Identity association for the ServiceAccount; with IRSA, the ServiceAccount needs the role annotation and a valid OIDC trust policy.&lt;/p&gt;

&lt;p&gt;The chart's default hostPath mounts must also be verified against your node runtime. The above values are a reference configuration to be validated, not a guarantee that every EKS node image exposes identical log paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm upgrade &lt;span class="nt"&gt;--install&lt;/span&gt; realestate-logs &lt;span class="se"&gt;\&lt;/span&gt;
  fluent/fluent-bit &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; logging &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; fluent-values.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get daemonsets &lt;span class="nt"&gt;-n&lt;/span&gt; logging
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; logging &lt;span class="nt"&gt;-o&lt;/span&gt; wide
kubectl logs &lt;span class="nt"&gt;-n&lt;/span&gt; logging &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;fluent-bit &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  10.4 Verify centralized logs
&lt;/h3&gt;

&lt;p&gt;Generate some backend traffic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"http://&lt;/span&gt;&lt;span class="nv"&gt;$ALB_DNS&lt;/span&gt;&lt;span class="s2"&gt;/api/properties"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then inspect CloudWatch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws logs describe-log-streams &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--log-group-name&lt;/span&gt; /jumptotech/real-estate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read recent logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws logs &lt;span class="nb"&gt;tail&lt;/span&gt; /jumptotech/real-estate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--since&lt;/span&gt; 10m &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If no logs appear, inspect the Fluent Bit Pod logs, IAM permissions, log paths, filter configuration and output plugin errors.&lt;/p&gt;

&lt;p&gt;Student question: Why do we use DaemonSet rather than a Deployment with three replicas for a node-level log collector?&lt;/p&gt;

&lt;p&gt;Answer: A DaemonSet ties desired Pod placement to eligible nodes. A Deployment controls replica count but does not guarantee one collector on every node.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Phase 9 — Terraform and infrastructure ownership
&lt;/h2&gt;

&lt;p&gt;Terraform is an infrastructure-as-code tool. It can provision the AWS infrastructure that Kubernetes applications depend on.&lt;/p&gt;

&lt;p&gt;For this lab, divide ownership as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Managed by&lt;/th&gt;
&lt;th&gt;Responsible team&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPC, subnets, security groups&lt;/td&gt;
&lt;td&gt;Terraform / AWS&lt;/td&gt;
&lt;td&gt;Cloud / DevOps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EKS cluster and node groups&lt;/td&gt;
&lt;td&gt;Terraform / AWS&lt;/td&gt;
&lt;td&gt;Platform / DevOps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ECR repositories&lt;/td&gt;
&lt;td&gt;Terraform / AWS&lt;/td&gt;
&lt;td&gt;DevOps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RDS instance and subnet group&lt;/td&gt;
&lt;td&gt;Terraform / AWS&lt;/td&gt;
&lt;td&gt;Cloud / DBA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS IAM roles and policies&lt;/td&gt;
&lt;td&gt;Terraform / AWS&lt;/td&gt;
&lt;td&gt;Cloud Security / DevOps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend and backend code&lt;/td&gt;
&lt;td&gt;Git&lt;/td&gt;
&lt;td&gt;Application developers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployments and Services&lt;/td&gt;
&lt;td&gt;Kubernetes manifests / Helm&lt;/td&gt;
&lt;td&gt;DevOps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL StatefulSet and PVC&lt;/td&gt;
&lt;td&gt;Kubernetes&lt;/td&gt;
&lt;td&gt;DevOps / DBA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EBS volumes&lt;/td&gt;
&lt;td&gt;EBS CSI Driver / AWS&lt;/td&gt;
&lt;td&gt;Kubernetes storage integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fluent Bit&lt;/td&gt;
&lt;td&gt;Helm / DaemonSet&lt;/td&gt;
&lt;td&gt;Platform / SRE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database schema and migrations&lt;/td&gt;
&lt;td&gt;SQL migration tooling&lt;/td&gt;
&lt;td&gt;Backend / DBA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Terraform example: RDS security group
&lt;/h3&gt;

&lt;p&gt;This example demonstrates how to restrict PostgreSQL access to the EKS worker-node security group.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;terraform/rds-security.tf&lt;/code&gt; in a separate Terraform project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"vpc_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"eks_node_security_group_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"rds"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name_prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"realestate-rds-"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"RDS access from EKS worker nodes"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_id&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"JumpToTech-RealEstate"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc_security_group_ingress_rule"&lt;/span&gt; &lt;span class="s2"&gt;"postgres"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;security_group_id&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;referenced_security_group_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_node_security_group_id&lt;/span&gt;
  &lt;span class="nx"&gt;ip_protocol&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;                    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;                      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc_security_group_egress_rule"&lt;/span&gt; &lt;span class="s2"&gt;"rds_egress"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;security_group_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_ipv4&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;
  &lt;span class="nx"&gt;ip_protocol&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is only one component of the RDS Terraform configuration, not a complete standalone infrastructure deployment. The VPC, provider, DB subnet group, RDS instance, credential management and Terraform backend still need to be configured.&lt;/p&gt;

&lt;p&gt;Important: Students must never run &lt;code&gt;terraform apply&lt;/code&gt; against an existing shared EKS infrastructure project without understanding its state and proposed changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Phase 10 — Production troubleshooting exercises
&lt;/h2&gt;

&lt;p&gt;Each student must investigate these scenarios independently and explain the findings.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Symptoms&lt;/th&gt;
&lt;th&gt;First checks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ImagePullBackOff&lt;/td&gt;
&lt;td&gt;Pod cannot start&lt;/td&gt;
&lt;td&gt;Image URI, ECR tag, pull permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CrashLoopBackOff&lt;/td&gt;
&lt;td&gt;Container repeatedly exits&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;kubectl logs --previous&lt;/code&gt;, events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend not Ready&lt;/td&gt;
&lt;td&gt;Readiness probe fails&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/readyz&lt;/code&gt;, RDS connectivity, credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service unavailable&lt;/td&gt;
&lt;td&gt;No backend endpoints&lt;/td&gt;
&lt;td&gt;Selectors, Pod labels, EndpointSlices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ALB 502&lt;/td&gt;
&lt;td&gt;ALB cannot get valid backend response&lt;/td&gt;
&lt;td&gt;Target health, ports, app process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ALB 503&lt;/td&gt;
&lt;td&gt;No available targets or other service issue&lt;/td&gt;
&lt;td&gt;Target groups, endpoints, health&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ALB 504&lt;/td&gt;
&lt;td&gt;Backend response timeout&lt;/td&gt;
&lt;td&gt;Application latency, networking, RDS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PVC Pending&lt;/td&gt;
&lt;td&gt;PostgreSQL cannot obtain storage&lt;/td&gt;
&lt;td&gt;StorageClass, CSI driver, IAM, scheduling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL Pod Pending&lt;/td&gt;
&lt;td&gt;Pod cannot schedule&lt;/td&gt;
&lt;td&gt;Node capacity, AZ constraints, volume events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fluent Bit no logs&lt;/td&gt;
&lt;td&gt;CloudWatch log group empty&lt;/td&gt;
&lt;td&gt;IAM, input path, collector logs, output errors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Troubleshooting commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;-o&lt;/span&gt; wide

kubectl describe deployment realestate-backend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab

kubectl logs deployment/realestate-backend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100

kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab

kubectl get endpointslices &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab

kubectl get events &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--sort-by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.lastTimestamp

kubectl get pvc &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab

kubectl describe pvc postgres-data-postgres-0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab

kubectl get daemonsets &lt;span class="nt"&gt;-A&lt;/span&gt;

kubectl get ingress &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Simulated production incident
&lt;/h3&gt;

&lt;p&gt;Your instructor will introduce a problem.&lt;/p&gt;

&lt;p&gt;Incident: Customers can open the Real Estate Company website, but submitting an inquiry fails.&lt;/p&gt;

&lt;p&gt;Students must:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify whether the frontend is available.&lt;/li&gt;
&lt;li&gt;Check the backend HTTP response.&lt;/li&gt;
&lt;li&gt;Inspect backend Pod readiness.&lt;/li&gt;
&lt;li&gt;Check Service selectors and EndpointSlices.&lt;/li&gt;
&lt;li&gt;Examine application logs.&lt;/li&gt;
&lt;li&gt;Test PostgreSQL connectivity.&lt;/li&gt;
&lt;li&gt;Identify the root cause.&lt;/li&gt;
&lt;li&gt;Propose a safe correction.&lt;/li&gt;
&lt;li&gt;Verify that inquiries can be saved again.&lt;/li&gt;
&lt;li&gt;Write a short incident report.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not delete a namespace or restart all workloads as your first troubleshooting action.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. Final student assessment
&lt;/h2&gt;

&lt;p&gt;Student completion checklist&lt;/p&gt;

&lt;p&gt;0/12 complete&lt;/p&gt;

&lt;p&gt;Frontend and backend container images pushed to ECR&lt;/p&gt;

&lt;p&gt;Frontend and backend Deployments running&lt;/p&gt;

&lt;p&gt;ClusterIP Services and EndpointSlices verified&lt;/p&gt;

&lt;p&gt;ALB routes frontend and backend traffic&lt;/p&gt;

&lt;p&gt;RDS PostgreSQL connected to Backend&lt;/p&gt;

&lt;p&gt;Customer inquiry saved and retrieved&lt;/p&gt;

&lt;p&gt;PostgreSQL StatefulSet created&lt;/p&gt;

&lt;p&gt;PVC Bound to an EBS-backed PV&lt;/p&gt;

&lt;p&gt;PostgreSQL data survives Pod replacement&lt;/p&gt;

&lt;p&gt;Fluent Bit DaemonSet deployed&lt;/p&gt;

&lt;p&gt;CloudWatch receives application logs&lt;/p&gt;

&lt;p&gt;One incident investigated and documented&lt;/p&gt;

&lt;h3&gt;
  
  
  Interview questions
&lt;/h3&gt;

&lt;p&gt;Students should be able to answer these questions in English without reading notes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is the difference between Deployment and StatefulSet?&lt;/li&gt;
&lt;li&gt;Why does the frontend use a Deployment?&lt;/li&gt;
&lt;li&gt;Why do we use ClusterIP Services?&lt;/li&gt;
&lt;li&gt;What is the difference between Amazon RDS and PostgreSQL in a StatefulSet?&lt;/li&gt;
&lt;li&gt;What happens if the PostgreSQL Pod is deleted?&lt;/li&gt;
&lt;li&gt;What is the difference between PV, PVC and StorageClass?&lt;/li&gt;
&lt;li&gt;What does the EBS CSI Driver do?&lt;/li&gt;
&lt;li&gt;Why is a DaemonSet suitable for a log collector?&lt;/li&gt;
&lt;li&gt;What is the difference between a DaemonSet controller and kubelet?&lt;/li&gt;
&lt;li&gt;How do you troubleshoot a backend Pod that is Running but not Ready?&lt;/li&gt;
&lt;li&gt;What is the purpose of AWS IAM in this architecture?&lt;/li&gt;
&lt;li&gt;How does a customer HTTP request travel from ALB to PostgreSQL?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  14. Cleanup — prevent unnecessary AWS charges
&lt;/h2&gt;

&lt;p&gt;Do not delete resources from a shared or production cluster. Confirm the namespace and ownership before cleanup.&lt;/p&gt;

&lt;p&gt;First inspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
kubectl get pvc &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
kubectl get ingress &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove the ALB Ingress and verify that the AWS Load Balancer Controller has deleted the corresponding ALB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete ingress realestate-ingress &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uninstall Fluent Bit if it was installed specifically for this lab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm uninstall realestate-logs &lt;span class="nt"&gt;-n&lt;/span&gt; logging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove the StatefulSet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete statefulset postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The StatefulSet's PVC is generally retained when the StatefulSet is deleted. Inspect the PVC and PV before deleting storage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pvc &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
kubectl get pv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the PostgreSQL data is disposable and the PVC belongs to this lab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pvc postgres-data-postgres-0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; real-estate-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the lab's &lt;code&gt;Delete&lt;/code&gt; reclaim policy, this can cause the backing EBS volume to be deleted. Verify the actual EBS resource state in AWS.&lt;/p&gt;

&lt;p&gt;After verifying that all resources in the namespace belong to this lab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete namespace real-estate-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove the lab-specific RDS instance, snapshots, CloudWatch log group, ECR images, IAM associations and other AWS resources only after verifying their ownership and backup requirements. Deleting the Kubernetes namespace does not automatically delete Amazon RDS.&lt;/p&gt;

&lt;p&gt;Do not delete the EKS cluster if other students or projects use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  15. What students must submit
&lt;/h2&gt;

&lt;p&gt;Each student must submit a GitHub repository link and a short lab report containing evidence of the deployment, networking, database persistence, logging and troubleshooting.&lt;/p&gt;

&lt;p&gt;The report should explain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why the frontend and backend use Deployments.&lt;/li&gt;
&lt;li&gt;Why RDS is separate from Kubernetes.&lt;/li&gt;
&lt;li&gt;How StatefulSet, PVC, PV, StorageClass and EBS CSI work together.&lt;/li&gt;
&lt;li&gt;Why the log collector uses a DaemonSet.&lt;/li&gt;
&lt;li&gt;Which Kubernetes controllers are responsible for maintaining the desired state.&lt;/li&gt;
&lt;li&gt;What failed during troubleshooting and how the student verified recovery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Students must not commit passwords, &lt;code&gt;.env&lt;/code&gt; secrets, kubeconfig credentials or AWS access keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final teaching outcome
&lt;/h3&gt;

&lt;p&gt;By the end of this project, you should be able to explain the architecture of a multi-tier application on AWS EKS and demonstrate how its components work together.&lt;/p&gt;

&lt;p&gt;The goal is not simply to create Pods. The goal is to understand application deployment, networking, database persistence, AWS permissions, observability and production troubleshooting.&lt;/p&gt;

&lt;p&gt;Instructor implementation note: The application and Kubernetes examples above form a reference lab, but several infrastructure prerequisites are environment-specific: EKS IAM configuration, ALB controller installation, RDS networking and credentials, EBS CSI installation, and Fluent Bit AWS permissions. These must be validated against the actual student cluster before calling the deployment fully operational.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>THRIVE MARKET SRE – TECHNICAL INTERVIEW PREP, questions and answers for Aisel for the next step</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Mon, 02 Nov 2026 22:08:46 +0000</pubDate>
      <link>https://dev.to/jumptotech/thrive-market-sre-technical-interview-prep-questions-and-answers-for-aisel-for-the-next-step-16df</link>
      <guid>https://dev.to/jumptotech/thrive-market-sre-technical-interview-prep-questions-and-answers-for-aisel-for-the-next-step-16df</guid>
      <description>&lt;p&gt;PART 1. WHAT YOU KNOW ABOUT THRIVE (use this in your answers)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Company is 10+ years old, everything runs on AWS.&lt;/li&gt;
&lt;li&gt;Core app is PHP, mostly APIs for mobile apps, plus smaller APIs.&lt;/li&gt;
&lt;li&gt;They moved from a Puppet-based system to Kubernetes on EKS.&lt;/li&gt;
&lt;li&gt;CI is GitHub Actions, CD is Argo CD.&lt;/li&gt;
&lt;li&gt;Still have legacy systems in different AWS accounts. They want to move them into the main prod account (caches, ALBs, services).&lt;/li&gt;
&lt;li&gt;Biggest priorities: cost, legacy migration, Kubernetes work.&lt;/li&gt;
&lt;li&gt;Most incidents are app-related: DB slowness or cache issues make PHP-FPM workers fill up, Nginx upstream queues grow, error rate goes up.&lt;/li&gt;
&lt;li&gt;One past infra issue: CPU steal on Kubernetes nodes.&lt;/li&gt;
&lt;li&gt;They care about early signals, SLOs, and error rate. They are starting to use AI for monitoring.&lt;/li&gt;
&lt;li&gt;They scale on PHP-FPM busy workers, not CPU, because CPU is a late signal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use these words in your answers: early signals, user impact, step by step, reduce cost, reduce risk, root cause.&lt;/p&gt;

&lt;p&gt;PART 2. KEEP YOUR STORY CONSISTENT&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current/last company: FitTech (Senior SRE, Jan 2024 – now). Update the resume.&lt;/li&gt;
&lt;li&gt;Home Depot: DevOps Engineer, 2022–2023.&lt;/li&gt;
&lt;li&gt;XPO Logistics: Cloud/DevOps Engineer, 2020–2021.&lt;/li&gt;
&lt;li&gt;Cost savings: 28% everywhere.&lt;/li&gt;
&lt;li&gt;Be ready to explain the 28%: rightsizing EC2 and EKS nodes, tuning pod requests, deleting unused EBS/snapshots/ALBs, shutting down dev/test at night, Terraform defaults, cost alerts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PART 3. KUBERNETES&lt;/p&gt;

&lt;p&gt;Troubleshooting order (say it out loud like this):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;kubectl get pods -n ns – check status.&lt;/li&gt;
&lt;li&gt;kubectl describe pod – read Events at the bottom.&lt;/li&gt;
&lt;li&gt;kubectl logs pod, and kubectl logs pod --previous if it crashed.&lt;/li&gt;
&lt;li&gt;kubectl get svc, kubectl get endpoints – does the Service selector match pod labels?&lt;/li&gt;
&lt;li&gt;Check Ingress / ALB target health.&lt;/li&gt;
&lt;li&gt;Check what changed in Git / Argo CD. If urgent, roll back first.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Common pod states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pending: not enough CPU/memory on nodes, node selector or taint problem, PVC not bound.&lt;/li&gt;
&lt;li&gt;ImagePullBackOff: wrong image name/tag, no ECR permission.&lt;/li&gt;
&lt;li&gt;CrashLoopBackOff: app starts and crashes. Check logs, env vars, secrets, config.&lt;/li&gt;
&lt;li&gt;OOMKilled: memory limit too low or memory leak.&lt;/li&gt;
&lt;li&gt;Running but not Ready: readiness probe failing, so no traffic.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Readiness: is the pod ready to get traffic? If it fails, pod is removed from Service.&lt;/li&gt;
&lt;li&gt;Liveness: is the app stuck? If it fails, container restarts.&lt;/li&gt;
&lt;li&gt;Startup: for slow-starting apps, protects from liveness killing it too early.&lt;/li&gt;
&lt;li&gt;Tip: liveness should NOT check the database. If DB is slow, all pods restart and make it worse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Requests and limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requests: what the scheduler reserves. Used for placement and cost.&lt;/li&gt;
&lt;li&gt;Limits: the max. Over memory limit = OOMKilled. Over CPU limit = throttled.&lt;/li&gt;
&lt;li&gt;Requests too high = wasted money. Too low = noisy neighbors and evictions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scaling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HPA: scales pods. Default on CPU/memory, but can use custom metrics.&lt;/li&gt;
&lt;li&gt;Custom metrics: Prometheus Adapter, or KEDA (easier, scales on Prometheus queries).&lt;/li&gt;
&lt;li&gt;Cluster Autoscaler or Karpenter: adds/removes nodes. Karpenter is faster and picks cheaper instance types.&lt;/li&gt;
&lt;li&gt;PDB (PodDisruptionBudget): keeps a minimum number of pods during node drains and upgrades.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deployments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rolling update: maxSurge and maxUnavailable control speed.&lt;/li&gt;
&lt;li&gt;Blue/green: two versions, switch traffic at once, easy rollback.&lt;/li&gt;
&lt;li&gt;Canary: small % of traffic first (Argo Rollouts can do this).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Networking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service types: ClusterIP (internal), NodePort, LoadBalancer.&lt;/li&gt;
&lt;li&gt;Ingress with AWS Load Balancer Controller creates ALBs. Use IngressGroup to share one ALB across many services. This saves money (good for their consolidation).&lt;/li&gt;
&lt;li&gt;DNS problems: check CoreDNS pods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RBAC for access, namespaces per team.&lt;/li&gt;
&lt;li&gt;IRSA (IAM Roles for Service Accounts) or EKS Pod Identity, so pods get AWS access without static keys.&lt;/li&gt;
&lt;li&gt;Network Policies to limit pod-to-pod traffic.&lt;/li&gt;
&lt;li&gt;Secrets: AWS Secrets Manager with External Secrets Operator.&lt;/li&gt;
&lt;li&gt;Image scanning in CI (Trivy) and ECR scanning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PART 4. PHP-FPM AND NGINX (very important for Thrive)&lt;/p&gt;

&lt;p&gt;How it breaks:&lt;br&gt;
DB or cache gets slow → PHP-FPM workers wait → all workers busy → requests wait in listen queue → Nginx upstream timeouts → 502/504 errors → users feel it.&lt;/p&gt;

&lt;p&gt;What to monitor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PHP-FPM: active processes, idle processes, max children reached, listen queue, slow requests.&lt;/li&gt;
&lt;li&gt;Nginx: upstream response time, 5xx rate, active connections.&lt;/li&gt;
&lt;li&gt;Tool: php-fpm status page + php-fpm exporter for Prometheus.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to scale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scale on busy worker % (for example 70–80%) or listen queue, not CPU.&lt;/li&gt;
&lt;li&gt;Use KEDA or HPA with Prometheus custom metrics.&lt;/li&gt;
&lt;li&gt;Warning: if DB is the root cause, more PHP pods = more DB connections = worse. Use connection limits, pooling (RDS Proxy for MySQL/Postgres), and check DB latency first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pm.max_children: max workers per pod. Size it by memory: pod memory / memory per worker.&lt;/li&gt;
&lt;li&gt;request_terminate_timeout and Nginx timeouts: so stuck requests don't hold workers forever.&lt;/li&gt;
&lt;li&gt;Timeouts to DB and cache in the app, so one slow dependency doesn't take everything down.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PART 5. OBSERVABILITY AND SLOs&lt;/p&gt;

&lt;p&gt;Four golden signals: latency, traffic, errors, saturation.&lt;/p&gt;

&lt;p&gt;SLI, SLO, error budget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SLI: what you measure. Example: % of requests that succeed in under 300 ms.&lt;/li&gt;
&lt;li&gt;SLO: the target. Example: 99.9% over 30 days.&lt;/li&gt;
&lt;li&gt;Error budget: 0.1% allowed failures. If used up, slow down releases and fix reliability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Burn rate alerts (impress them with this):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Burn rate = how fast you use the error budget.&lt;/li&gt;
&lt;li&gt;Fast burn: for example 14x over 1 hour → page right away.&lt;/li&gt;
&lt;li&gt;Slow burn: for example 2–3x over 6 hours → ticket or warning.&lt;/li&gt;
&lt;li&gt;Better than fixed thresholds: fewer false alerts, catches real problems early.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leading vs lagging signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leading (early): PHP-FPM queue growing, cache hit rate dropping, DB latency going up, connection count rising.&lt;/li&gt;
&lt;li&gt;Lagging (late): CPU, error rate, users complaining.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alerting rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page only on user impact (errors, latency, SLO burn).&lt;/li&gt;
&lt;li&gt;Everything else goes to dashboards or warnings.&lt;/li&gt;
&lt;li&gt;Every alert must be actionable and have a runbook.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Monitoring a web app + cache + RDS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App: request rate, 5xx rate, p95/p99 latency, pod restarts.&lt;/li&gt;
&lt;li&gt;Cache (ElastiCache Redis): hit rate, evictions, memory, connections, latency.&lt;/li&gt;
&lt;li&gt;RDS: CPU, FreeableMemory, FreeStorageSpace, DatabaseConnections, Read/Write latency, IOPS, DiskQueueDepth, ReplicaLag. Turn on Performance Insights for slow queries. RDS events to SNS.&lt;/li&gt;
&lt;li&gt;ALB: UnHealthyHostCount, HTTPCode_ELB_5XX, TargetResponseTime.&lt;/li&gt;
&lt;li&gt;Nodes: CPU steal time (their past issue).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CPU steal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Means the hypervisor is giving CPU time to other VMs.&lt;/li&gt;
&lt;li&gt;Common on burstable instances (t3) when credits run out.&lt;/li&gt;
&lt;li&gt;Fix: use non-burstable types (m5/m6i/m7i), or check t3 unlimited, and monitor node_cpu_seconds_total{mode="steal"}.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI in monitoring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anomaly detection (Datadog Watchdog, CloudWatch anomaly detection) catches unusual patterns.&lt;/li&gt;
&lt;li&gt;AI helps summarize incidents and logs, but humans still decide.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PART 6. AWS&lt;/p&gt;

&lt;p&gt;Multi-account consolidation (their big project):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inventory what runs in each account (services, caches, ALBs, DBs, costs).&lt;/li&gt;
&lt;li&gt;Plan the order: low-risk services first.&lt;/li&gt;
&lt;li&gt;Networking: VPC peering or Transit Gateway so accounts can talk during migration.&lt;/li&gt;
&lt;li&gt;Move service into the main EKS cluster with Terraform + Argo CD.&lt;/li&gt;
&lt;li&gt;Share ALBs with IngressGroup, combine caches where safe.&lt;/li&gt;
&lt;li&gt;Shift traffic slowly with Route 53 weighted records.&lt;/li&gt;
&lt;li&gt;Monitor, then turn off the old resources.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cost optimization list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rightsize EC2 and EKS nodes, tune pod requests.&lt;/li&gt;
&lt;li&gt;Karpenter for better node packing and cheaper instances.&lt;/li&gt;
&lt;li&gt;Spot instances for stateless workloads and dev/test.&lt;/li&gt;
&lt;li&gt;Savings Plans / Reserved Instances for steady prod usage.&lt;/li&gt;
&lt;li&gt;Graviton (ARM) instances: about 20% cheaper.&lt;/li&gt;
&lt;li&gt;Delete unused EBS volumes, snapshots, old ALBs, unattached Elastic IPs.&lt;/li&gt;
&lt;li&gt;Move gp2 to gp3 volumes (cheaper).&lt;/li&gt;
&lt;li&gt;NAT Gateway data costs: use VPC endpoints for S3 and ECR.&lt;/li&gt;
&lt;li&gt;S3 lifecycle policies.&lt;/li&gt;
&lt;li&gt;Shut down dev/test at night and weekends.&lt;/li&gt;
&lt;li&gt;Visibility: Cost Explorer, tags, Kubecost for cost per service/namespace.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RDS basics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-AZ for high availability (automatic failover).&lt;/li&gt;
&lt;li&gt;Read replicas for read scaling.&lt;/li&gt;
&lt;li&gt;Automated backups and snapshots.&lt;/li&gt;
&lt;li&gt;Private subnets, security groups, least privilege.&lt;/li&gt;
&lt;li&gt;RDS Proxy for connection pooling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PART 7. TERRAFORM&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remote state in S3 with DynamoDB locking.&lt;/li&gt;
&lt;li&gt;Modules to reuse code.&lt;/li&gt;
&lt;li&gt;terraform plan before apply, review in pull request.&lt;/li&gt;
&lt;li&gt;Run in CI (GitHub Actions) with plan output in the PR.&lt;/li&gt;
&lt;li&gt;terraform import to bring legacy resources into code (useful for their legacy accounts).&lt;/li&gt;
&lt;li&gt;Drift: when someone changes things by hand. Detect with scheduled plan.&lt;/li&gt;
&lt;li&gt;Never put secrets in code. Use Secrets Manager.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PART 8. CI/CD&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions: build, test, scan image, push to ECR, update Helm values or image tag in Git.&lt;/li&gt;
&lt;li&gt;Argo CD: watches Git and syncs to cluster (GitOps). Git is the source of truth.&lt;/li&gt;
&lt;li&gt;Rollback: revert the Git commit, or Argo CD rollback.&lt;/li&gt;
&lt;li&gt;Use OIDC from GitHub Actions to AWS, no long-lived keys.&lt;/li&gt;
&lt;li&gt;Safe deploys: small changes, canary or rolling, health checks, automatic rollback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PART 9. INCIDENT RESPONSE&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Detect (alert).&lt;/li&gt;
&lt;li&gt;Assess impact: how many users, which service.&lt;/li&gt;
&lt;li&gt;Communicate: incident channel, status updates.&lt;/li&gt;
&lt;li&gt;Mitigate first: rollback, scale, restart, failover. Fix users first, find root cause later.&lt;/li&gt;
&lt;li&gt;Find root cause.&lt;/li&gt;
&lt;li&gt;Blameless postmortem: timeline, root cause, action items.&lt;/li&gt;
&lt;li&gt;Follow up on action items.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Key words: MTTR, blameless, mitigation first, action items.&lt;/p&gt;

&lt;p&gt;PART 10. PRACTICE SCENARIOS (they may ask live)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Error rate suddenly goes up. What do you do?&lt;br&gt;
Check what changed (deploys in Argo CD). Check dashboards: is it one service or all? Check PHP-FPM workers, Nginx upstream, cache hit rate, RDS latency and connections. If a recent deploy, roll back. Then root cause.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Latency is high but CPU is low.&lt;br&gt;
Workers are waiting on something: DB, cache, or external API. Check RDS slow queries and Performance Insights, cache hit rate, PHP-FPM listen queue. CPU is low because workers are waiting, not working.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pods keep restarting.&lt;br&gt;
describe pod: OOMKilled or liveness failure? Logs with --previous. If OOM, raise memory or fix leak. If liveness, check if probe is too strict or checks the DB.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A node is NotReady.&lt;br&gt;
kubectl describe node, check kubelet, disk pressure, memory pressure. Cordon and drain if needed. Karpenter or ASG replaces it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RDS connections are at max.&lt;br&gt;
Find which app opens too many connections. Lower pm.max_children or pod count, add RDS Proxy, check for connection leaks. Short-term: kill idle connections carefully.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cache goes down.&lt;br&gt;
All traffic hits the DB, DB slows, PHP workers fill up. Protect the DB: rate limit, timeouts, ElastiCache Multi-AZ with replicas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduce AWS cost by 20% in 3 months.&lt;br&gt;
Get visibility first (Cost Explorer, Kubecost, tags). Quick wins: unused resources, gp3, dev/test schedules. Then rightsize, Karpenter, Spot for stateless, Savings Plans, Graviton. Track monthly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Migrate a legacy service from another account to EKS.&lt;br&gt;
See Part 6 steps. Containerize, add probes and monitoring, deploy with Argo CD, shift traffic with Route 53 weights, keep rollback ready.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PART 11. LINUX BASICS (quick review)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;top / htop: CPU and memory.&lt;/li&gt;
&lt;li&gt;df -h: disk space. du -sh: folder size.&lt;/li&gt;
&lt;li&gt;free -m: memory.&lt;/li&gt;
&lt;li&gt;ss -tulpn or netstat: open ports.&lt;/li&gt;
&lt;li&gt;curl -v: test HTTP.&lt;/li&gt;
&lt;li&gt;dig / nslookup: DNS.&lt;/li&gt;
&lt;li&gt;journalctl -u service: service logs.&lt;/li&gt;
&lt;li&gt;ps aux | grep php-fpm: processes.&lt;/li&gt;
&lt;li&gt;Load average vs number of CPUs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PART 12. QUESTIONS TO ASK (tech interview)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Are you scaling PHP-FPM with KEDA or HPA custom metrics?&lt;/li&gt;
&lt;li&gt;Do you use burn-rate alerts on your SLOs today?&lt;/li&gt;
&lt;li&gt;What is the next legacy account or service to migrate?&lt;/li&gt;
&lt;li&gt;Are you using Karpenter or Cluster Autoscaler, and any Spot?&lt;/li&gt;
&lt;li&gt;What would success look like in the first 90 days?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PART 13. TIPS FOR THE DAY&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you don't know something, say: "I haven't used that directly, but here is how I would approach it." Then explain your thinking.&lt;/li&gt;
&lt;li&gt;Think out loud in troubleshooting questions. They want to see your process.&lt;/li&gt;
&lt;li&gt;Always say: mitigate first, then root cause.&lt;/li&gt;
&lt;li&gt;Connect answers to their problems: PHP-FPM, cost, migration, early signals.&lt;/li&gt;
&lt;li&gt;Keep answers short, then give one real example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;THRIVE MARKET SRE – QUESTIONS AND ANSWERS&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT YOURSELF&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hi, my name is Aisel. I'm a Site Reliability Engineer with over 6 years of experience in AWS, Kubernetes, and production support.&lt;/p&gt;

&lt;p&gt;In my current role at FitTech, I manage production workloads on Amazon EKS. I build CI/CD pipelines with Jenkins and GitHub Actions, deploy with Helm and Argo CD, and manage AWS infrastructure with Terraform. I use Prometheus, Grafana, Datadog, and CloudWatch for monitoring, and I take part in incident response and root cause analysis. I also helped reduce our cloud costs by 28%.&lt;/p&gt;

&lt;p&gt;Before that, I was a DevOps Engineer at Home Depot, supporting a Kubernetes microservices platform, and at XPO Logistics, building AWS infrastructure with Terraform.&lt;/p&gt;

&lt;p&gt;I enjoy troubleshooting, finding root causes, and automating work so problems don't come back. This role is a great match because it focuses on Kubernetes migration, cost, and reliability, which is exactly what I've been doing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;WHAT ARE YOUR DAY-TO-DAY RESPONSIBILITIES?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My day usually starts with checking dashboards and alerts in Datadog and Grafana to make sure production is healthy. Then I review any issues from the night before.&lt;/p&gt;

&lt;p&gt;During the day I work on a mix of things: supporting deployments with Argo CD, fixing or improving CI/CD pipelines in GitHub Actions and Jenkins, writing Terraform for new infrastructure, and helping developers troubleshoot problems in Kubernetes.&lt;/p&gt;

&lt;p&gt;I also work on improvement projects, like cost optimization, better alerting, and automation with Bash and Python.&lt;/p&gt;

&lt;p&gt;When I'm on call, I respond to incidents, restore service, and then do root cause analysis and write the postmortem.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT A PROJECT YOU'RE PROUD OF (COST OPTIMIZATION)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At FitTech, our AWS bill was growing every month, and I was asked to reduce it.&lt;/p&gt;

&lt;p&gt;First, I looked at the data in AWS Cost Explorer, and at real CPU and memory usage in CloudWatch and Datadog. I found three main problems: oversized EC2 instances and EKS nodes, unused resources like old EBS volumes, snapshots, and load balancers, and dev and test environments running 24/7.&lt;/p&gt;

&lt;p&gt;Then I fixed them step by step. I rightsized instances and EKS node groups, tuned CPU and memory requests for pods, wrote Python and Bash scripts to find and clean unused resources, and scheduled dev and test to shut down at night and on weekends. I moved EBS volumes from gp2 to gp3. I also put the right sizes into Terraform, so new resources were created correctly, and set up cost alerts.&lt;/p&gt;

&lt;p&gt;The result was a 28% reduction in monthly cloud cost, with no impact on performance.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT ANOTHER PROJECT (MONITORING / SLOs)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At FitTech, our alerting was noisy. I had added many alerts on CPU, memory, and restarts, and on-call engineers were getting alert fatigue.&lt;/p&gt;

&lt;p&gt;I reviewed all the alerts with the team and removed or tuned the noisy ones. Then we moved to SLI and SLO based alerting, focused on what users feel: error rate and latency. We used burn-rate alerts, so we got paged when the error budget was being used too fast. CPU and memory moved to dashboards for troubleshooting.&lt;/p&gt;

&lt;p&gt;The result was far fewer alerts, almost every page was a real issue, and our MTTR went down because the team trusted the alerts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT A PROJECT (KUBERNETES RELIABILITY AT HOME DEPOT)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At Home Depot, many incidents happened during releases because pods received traffic before the app was ready, or stayed running when the app was stuck.&lt;/p&gt;

&lt;p&gt;I collected data from past incidents and proposed adding readiness and liveness probes. I tested it on one service first, showed the results, and then worked with developers to roll it out to other services. I also set up the ALB Ingress Controller and supported rolling and blue/green deployments.&lt;/p&gt;

&lt;p&gt;The result was fewer failed deployments and safer releases.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT AN INCIDENT YOU HANDLED&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At FitTech, one afternoon we got alerts that the error rate and latency on one of our main APIs were going up fast. Users were getting timeouts.&lt;/p&gt;

&lt;p&gt;First, I joined the incident channel and checked what changed. There was no recent deployment. In the dashboards, CPU on the pods looked normal, but latency was high, which told me the app was waiting on something. I checked the database and saw DatabaseConnections on RDS was almost at the max.&lt;/p&gt;

&lt;p&gt;To mitigate, we scaled down a background worker service that was opening too many connections, and the errors dropped within a few minutes.&lt;/p&gt;

&lt;p&gt;For root cause, we found a new batch job had been released earlier that day. It opened a new DB connection for every task and didn't close them. The developers fixed the connection handling, and we added connection pooling.&lt;/p&gt;

&lt;p&gt;After the postmortem, I added alerts on DB connections and latency as early warning signals, and we added connection limits for that service. We didn't have that problem again.&lt;/p&gt;

&lt;p&gt;What I learned: CPU can look fine while users are suffering, so watch dependencies like the database, and always mitigate first, then find the root cause.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT A TIME YOU COLLABORATED WITH DEVELOPERS&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At FitTech, a development team was having frequent deployment failures, and they felt it was an infrastructure problem.&lt;/p&gt;

&lt;p&gt;Instead of arguing about whose fault it was, I set up a meeting and we looked at the data together: Argo CD history, pod events, and logs. We found that most failures were from missing config values and wrong resource limits.&lt;/p&gt;

&lt;p&gt;We worked together on a fix. I added validation steps in the GitHub Actions pipeline to check Helm values before deploy, and they updated their resource settings. I also wrote a short runbook for them.&lt;/p&gt;

&lt;p&gt;Deployment failures dropped a lot, and the relationship between our teams got much better. I learned that good collaboration starts with shared data, not blame.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT A TIME YOU DISAGREED WITH YOUR MANAGER&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At FitTech, my manager wanted to deploy a big change to production all at once to save time. I was worried because it touched many services, and rollback would be hard.&lt;/p&gt;

&lt;p&gt;I talked to him one on one and explained the risk. I suggested deploying in smaller parts, starting with one low-risk service, using Argo CD for fast rollback. It only added about a day.&lt;/p&gt;

&lt;p&gt;He agreed. In the first small deploy, we found a config problem and fixed it in minutes with no customer impact. After that, smaller step-by-step deploys became our normal process.&lt;/p&gt;

&lt;p&gt;I learned to disagree with data and a clear solution, and to respect the final decision.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT A FAILURE OR MISTAKE&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At FitTech, I added many alerts with low thresholds, thinking more alerts would catch more problems. It created too much noise, and the team started getting alert fatigue.&lt;/p&gt;

&lt;p&gt;I owned it, reviewed the alerts with the team, removed the noisy ones, added time windows, and moved to SLO-based alerting on user impact.&lt;/p&gt;

&lt;p&gt;I learned that more alerts don't mean better monitoring. Every alert must be actionable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT A TIME YOU TOOK INITIATIVE&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At Home Depot, my team's plan was only to support deployments. But I noticed many incidents were caused by missing health checks.&lt;/p&gt;

&lt;p&gt;It wasn't in our plan, but I collected incident data, proposed readiness and liveness probes, tested on one service, showed the results, and then rolled it out with developers. It reduced failed deployments and made releases safer.&lt;/p&gt;

&lt;p&gt;I learned: when I see a problem, I collect data, start small, show results, and then get the team on board.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TELL ME ABOUT A TIME YOU HELPED A JUNIOR ENGINEER&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At Home Depot, a junior engineer deployed a service to Kubernetes and it wasn't working. I sat with him and we went step by step: get pods showed CrashLoopBackOff, logs showed a missing environment variable because of a typo in the secret name. After fixing it, the app still wasn't reachable, and we found the Service selector didn't match the pod labels.&lt;/p&gt;

&lt;p&gt;I didn't just fix it for him. I guided him, and then asked him to write a short runbook. Other new engineers started using it too.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HOW DO YOU HANDLE PRESSURE DURING AN OUTAGE?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I stay calm and focus on facts. First, I check impact and what changed. I communicate clearly in the incident channel, even if it's just "still investigating." I focus on restoring service first, then root cause later. Having good runbooks and dashboards also helps a lot under pressure.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HOW DO YOU PRIORITIZE WHEN MANY THINGS HAPPEN AT ONCE?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Production incidents and user impact always come first. Then I look at risk and urgency: security issues and things that could cause an outage next. Then planned project work. If priorities are not clear, I talk to my manager and the team so we agree on what's most important.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HOW DO YOU KEEP LEARNING?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I learn by doing: I set up small labs to test new tools like Karpenter and KEDA. I read AWS and Kubernetes documentation and blogs, and learn from postmortems at other companies. I also use AI tools to help me learn faster and write scripts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;WHAT ARE YOUR STRENGTHS?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm very good at troubleshooting. I stay calm, follow the data, and find the root cause. I also like automation, so I fix problems in a way that prevents them from coming back.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;WHAT IS YOUR WEAKNESS?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Earlier in my career, I sometimes tried to fix everything myself instead of asking for help quickly. I learned that during incidents, asking early and sharing information saves time. Now I communicate early and involve the right people quickly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HOW DO YOU USE AI IN YOUR WORK?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I use AI coding assistants to help write Bash and Python scripts, Terraform, and GitHub Actions workflows faster. I also use them to help explain errors and logs during troubleshooting. But I always review and test the output before using it in production.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;WHY THRIVE MARKET?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I like Thrive Market's mission of making healthy and sustainable products more accessible. And technically, this role matches my experience very well: migrating legacy systems to Kubernetes, AWS cost optimization, and improving reliability with better signals and SLOs. I'd love to help the team with those projects.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;WHY ARE YOU LOOKING FOR A NEW JOB?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(Choose the one that's true.)&lt;br&gt;
If the contract ended: My contract ended, and I'm looking for a long-term role where I can grow with a strong team.&lt;br&gt;
If still working: My contract is ending soon, and I'm looking for a long-term role where I can grow with a strong team.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SALARY EXPECTATIONS&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Based on the role and my experience, I'm targeting a base salary of $145,000 to $160,000. I'm flexible depending on the full compensation package.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;WHERE DO YOU SEE YOURSELF IN 3 TO 5 YEARS?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I want to grow into a senior or lead SRE role, where I help design reliable systems, guide other engineers, and drive bigger projects like platform improvements and cost strategy.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DO YOU HAVE ON-CALL EXPERIENCE?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Yes. At FitTech I'm part of the on-call rotation. I respond to alerts, restore service, communicate in the incident channel, and then help with root cause analysis and postmortems. I also work to reduce noisy alerts so on-call is sustainable for the team.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;QUESTIONS TO ASK THEM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What would success look like in the first 90 days?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the next legacy system or account you plan to migrate?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Are you using KEDA or HPA with custom metrics to scale PHP-FPM?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do you use burn-rate alerts on your SLOs?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How is on-call organized, and how big is the team?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CLOSING&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thank you for your time today. I'm really excited about this role. The Kubernetes migration, cost work, and reliability improvements are exactly what I enjoy and have done before. I believe I can help the team move faster and make the systems more reliable and cost-efficient. What are the next steps?&lt;/p&gt;

&lt;p&gt;Tip: practice each answer out loud 2 or 3 times. Don't memorize word by word, just remember the main steps of each story. If you want, I can quiz you one question at a time.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>kubernetes</category>
      <category>sre</category>
    </item>
    <item>
      <title>interview questions and answers based on real interview for Aizada</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Mon, 02 Nov 2026 22:03:29 +0000</pubDate>
      <link>https://dev.to/jumptotech/interview-questions-and-answers-based-on-real-interview-for-aizada-44ic</link>
      <guid>https://dev.to/jumptotech/interview-questions-and-answers-based-on-real-interview-for-aizada-44ic</guid>
      <description>&lt;p&gt;TELL ME ABOUT YOURSELF&lt;/p&gt;

&lt;p&gt;Hi, thank you for having me. I am a DevOps engineer focused on AWS, Kubernetes and automation. My education is in finance, so I understand budgets, cost and business value. Later I moved into technology because I love solving problems and automating things.&lt;/p&gt;

&lt;p&gt;In my work I build and support cloud infrastructure for development teams. I use Terraform to build reusable modules, so teams can create VPCs, EKS clusters, RDS and S3 in a standard and secure way. For delivery, I build CI/CD pipelines with GitHub Actions and Jenkins, and I use Helm and Argo CD for GitOps on EKS. I add security scanning in pipelines. For monitoring I use Prometheus, Grafana, CloudWatch and Datadog. I join production incidents, find root cause and fix it so it does not repeat.&lt;/p&gt;

&lt;p&gt;I have AWS Solutions Architect Associate and Terraform Associate certifications. I am excited about SOA because you are moving to Salesforce, building platform engineering and quality engineering, and focusing on safe delivery and reliability. That is exactly the work I enjoy.&lt;/p&gt;

&lt;p&gt;DAY TO DAY RESPONSIBILITIES&lt;/p&gt;

&lt;p&gt;Morning I check dashboards in Grafana and Datadog, alerts from the night, failed pipelines and open incidents.&lt;br&gt;
Standup with the team.&lt;br&gt;
Work on Jira tickets, like new environments, databases, S3 buckets or access requests. I do all of it with Terraform, never by hand in the console.&lt;br&gt;
Build and improve CI/CD pipelines, help developers when builds or deployments fail.&lt;br&gt;
Kubernetes work, update Helm charts, manage Argo CD apps, tune CPU and memory, HPA, RBAC, EKS upgrades.&lt;br&gt;
Security work, fix scan findings, rotate secrets, review IAM permissions.&lt;br&gt;
Add dashboards and alerts for new services, clean noisy alerts.&lt;br&gt;
Review Terraform and pipeline pull requests from teammates.&lt;br&gt;
On call and incidents, then root cause analysis.&lt;br&gt;
Write runbooks and documentation so developers can self serve.&lt;/p&gt;

&lt;p&gt;Short version: half my time is building and automating, half is supporting developers and keeping production healthy.&lt;/p&gt;

&lt;p&gt;MAIN PROJECT STORY&lt;/p&gt;

&lt;p&gt;I worked on a platform with more than 100 microservices running on Amazon EKS.&lt;/p&gt;

&lt;p&gt;Problem: teams deployed in different ways, some with Jenkins scripts, some with kubectl by hand. Deployments took 40 to 45 minutes, failed often, and it was hard to know what version was in production.&lt;/p&gt;

&lt;p&gt;What I did: I built EKS clusters with Terraform modules, VPC, node groups, IAM roles and add ons. I created a standard Helm chart template for all services. I set up Argo CD for GitOps, so merge to Git means automatic deploy. I improved pipelines with Docker layer caching, multi stage builds, dependency caching and parallel tests. I added Trivy image scanning and SonarQube. I set up HPA autoscaling, RBAC, and secrets in AWS Secrets Manager. I set up Prometheus, Grafana and alerts.&lt;/p&gt;

&lt;p&gt;Result: deployments went from about 40 minutes to about 12 minutes, around 70 percent faster. Fewer failed deployments, rollback became one git revert, and teams could deploy without waiting for DevOps.&lt;/p&gt;

&lt;p&gt;My part versus others: I owned the platform and the delivery path. Developers owned their code, Dockerfiles and their Helm values. QA owned testing. Security reviewed scan results and policies.&lt;/p&gt;

&lt;p&gt;TECHNICAL QUESTIONS WITH SHORT ANSWERS&lt;/p&gt;

&lt;p&gt;AWS&lt;/p&gt;

&lt;p&gt;Q: How do you design a highly available app on AWS?&lt;br&gt;
A: VPC with public and private subnets in at least two or three availability zones. ALB in public subnets, apps in private subnets on EKS or EC2 with auto scaling, RDS Multi AZ, NAT gateway for outbound, Route 53 for DNS, backups and CloudWatch alarms.&lt;/p&gt;

&lt;p&gt;Q: Difference between security group and NACL?&lt;br&gt;
A: Security group is on the instance level and is stateful, return traffic is allowed automatically. NACL is on the subnet level and is stateless, you must allow both directions. Security groups have only allow rules, NACL has allow and deny.&lt;/p&gt;

&lt;p&gt;Q: Public subnet versus private subnet?&lt;br&gt;
A: Public subnet has a route to the internet gateway. Private subnet has no direct internet access, it goes out through a NAT gateway.&lt;/p&gt;

&lt;p&gt;Q: How do you give an app in EKS access to S3 safely?&lt;br&gt;
A: IRSA or EKS Pod Identity. The pod gets an IAM role with least privilege, no access keys in code.&lt;/p&gt;

&lt;p&gt;Q: How do you reduce AWS cost?&lt;br&gt;
A: Right size instances, auto scaling, savings plans or reserved instances, spot for non critical workloads, delete unused resources, S3 lifecycle rules, and tags to see cost by team. Show reports with Cost Explorer.&lt;/p&gt;

&lt;p&gt;TERRAFORM&lt;/p&gt;

&lt;p&gt;Q: What is Terraform state and where do you keep it?&lt;br&gt;
A: State is the file that maps Terraform code to real resources. I keep it in S3 with encryption and versioning, and DynamoDB or S3 native locking so two people cannot change it at the same time.&lt;/p&gt;

&lt;p&gt;Q: How do you structure Terraform for many environments?&lt;br&gt;
A: Reusable modules for VPC, EKS, RDS, S3. Separate folders or workspaces for dev, stage and prod, each with its own state and variables. Modules are versioned in Git.&lt;/p&gt;

&lt;p&gt;Q: What happens if someone changes a resource by hand in the console?&lt;br&gt;
A: That is drift. terraform plan shows it. I either import the change into code or apply to bring it back. To prevent it, limit console write access and run plan regularly in a pipeline.&lt;/p&gt;

&lt;p&gt;Q: How do you run Terraform in CI/CD?&lt;br&gt;
A: On pull request, run fmt, validate, tflint, Checkov or tfsec, and plan, and post the plan in the PR. After approval and merge, run apply. Prod needs manual approval.&lt;/p&gt;

&lt;p&gt;Q: terraform import, taint, and lifecycle?&lt;br&gt;
A: Import brings an existing resource into state. Taint, now replace flag, forces recreate. Lifecycle lets me use prevent_destroy, create_before_destroy and ignore_changes.&lt;/p&gt;

&lt;p&gt;KUBERNETES&lt;/p&gt;

&lt;p&gt;Q: Explain Deployment, Service, Ingress.&lt;br&gt;
A: Deployment manages pods and rolling updates. Service gives a stable IP and DNS for pods. Ingress routes outside HTTP traffic to services, on EKS usually with the AWS Load Balancer Controller.&lt;/p&gt;

&lt;p&gt;Q: Pod is in CrashLoopBackOff, what do you do?&lt;br&gt;
A: kubectl describe pod to see events, kubectl logs and logs with previous flag. Common causes are wrong config or secret, app error, failed health probe, or OOMKilled because of low memory limit.&lt;/p&gt;

&lt;p&gt;Q: Pod is Pending?&lt;br&gt;
A: Usually not enough CPU or memory on nodes, node selector or taints do not match, or PVC not bound. Check describe pod events, then add nodes or fix requests.&lt;/p&gt;

&lt;p&gt;Q: Requests versus limits?&lt;br&gt;
A: Request is what the scheduler reserves. Limit is the maximum. If memory goes over the limit, the pod is OOMKilled. CPU over the limit is throttled.&lt;/p&gt;

&lt;p&gt;Q: How does HPA work?&lt;br&gt;
A: It watches metrics like CPU or memory from metrics server, or custom metrics, and adds or removes pods to keep the target. For nodes, Cluster Autoscaler or Karpenter adds nodes.&lt;/p&gt;

&lt;p&gt;Q: Liveness versus readiness probe?&lt;br&gt;
A: Readiness says if the pod can get traffic. Liveness says if the pod is stuck and should restart.&lt;/p&gt;

&lt;p&gt;Q: How do you manage secrets in Kubernetes?&lt;br&gt;
A: Not plain in Git. I use AWS Secrets Manager with External Secrets Operator or Secrets Store CSI driver, and RBAC to limit who can read them.&lt;/p&gt;

&lt;p&gt;Q: How do you upgrade EKS?&lt;br&gt;
A: Read release notes and check deprecated APIs, upgrade in dev first, upgrade control plane, then add ons, then node groups with rolling replacement. Use PodDisruptionBudgets so apps stay up.&lt;/p&gt;

&lt;p&gt;CI/CD AND GITOPS&lt;/p&gt;

&lt;p&gt;Q: Describe a good pipeline.&lt;br&gt;
A: Build, unit tests, code scan, dependency scan, build Docker image, image scan, push to ECR, update Helm values in Git, Argo CD deploys to dev, then integration and smoke tests, approval, then stage and prod.&lt;/p&gt;

&lt;p&gt;Q: Blue green versus canary?&lt;br&gt;
A: Blue green runs two full environments and switches all traffic at once, easy rollback. Canary sends a small percent of traffic to the new version first, like 10 percent, watches metrics, then increases. I can do canary with Argo Rollouts.&lt;/p&gt;

&lt;p&gt;Q: What is GitOps?&lt;br&gt;
A: Git is the single source of truth. Argo CD watches the repo and syncs the cluster to match Git. Every change has history and rollback is a git revert.&lt;/p&gt;

&lt;p&gt;Q: How do you roll back a bad deployment?&lt;br&gt;
A: With Argo CD, revert the commit or roll back to the previous synced version. With Helm, helm rollback. With canary, stop and abort the rollout.&lt;/p&gt;

&lt;p&gt;Q: How do you keep secrets safe in GitHub Actions?&lt;br&gt;
A: GitHub secrets or better, OIDC to assume an AWS role, so no long term AWS keys are stored at all.&lt;/p&gt;

&lt;p&gt;Q: Have you used Azure DevOps?&lt;br&gt;
A: My main experience is GitHub Actions and Jenkins. Azure DevOps pipelines use the same ideas, YAML stages, jobs, approvals and service connections, so I can pick it up quickly.&lt;/p&gt;

&lt;p&gt;SECURITY AND DEVSECOPS&lt;/p&gt;

&lt;p&gt;Q: What is SAST, DAST and SCA?&lt;br&gt;
A: SAST scans source code, like SonarQube. DAST tests the running app from outside, like OWASP ZAP. SCA scans third party libraries for known vulnerabilities, like Snyk or Dependabot.&lt;/p&gt;

&lt;p&gt;Q: How do you add security to pipelines without slowing teams?&lt;br&gt;
A: Run fast scans on every PR, deeper scans nightly. Block only critical and high issues, report the rest. Give developers clear results in the PR.&lt;/p&gt;

&lt;p&gt;Q: How do you handle IAM?&lt;br&gt;
A: Least privilege, roles not users, SSO with MFA, no root usage, regular access review, and CloudTrail for audit.&lt;/p&gt;

&lt;p&gt;Q: SSO and federation?&lt;br&gt;
A: Users log in once with an identity provider like Okta or Azure AD, and AWS or apps trust it through SAML or OIDC. In AWS I use IAM Identity Center connected to the identity provider.&lt;/p&gt;

&lt;p&gt;OBSERVABILITY AND SRE&lt;/p&gt;

&lt;p&gt;Q: Metrics, logs and traces?&lt;br&gt;
A: Metrics show numbers over time like CPU and error rate. Logs show detailed events. Traces show one request across many services. Together they help find problems fast.&lt;/p&gt;

&lt;p&gt;Q: What is SLI, SLO, SLA?&lt;br&gt;
A: SLI is the measurement, like percent of successful requests. SLO is our internal target, like 99.9 percent. SLA is the promise to customers with consequences. Error budget is how much failure we allow, if we use it up we slow down releases and fix reliability.&lt;/p&gt;

&lt;p&gt;Q: How do you avoid alert fatigue?&lt;br&gt;
A: Alert on symptoms users feel, like error rate and latency, not every CPU spike. Every alert must have an action and a runbook. Route by severity in PagerDuty or Opsgenie.&lt;/p&gt;

&lt;p&gt;Q: What are golden signals?&lt;br&gt;
A: Latency, traffic, errors and saturation.&lt;/p&gt;

&lt;p&gt;Q: New Relic or Splunk experience?&lt;br&gt;
A: I used Datadog, Prometheus and Grafana. New Relic is the same idea, APM, metrics, logs and alerts, so I can learn it fast.&lt;/p&gt;

&lt;p&gt;Q: What is AIOps and how do you use AI?&lt;br&gt;
A: AIOps uses machine learning to find anomalies, group related alerts and predict problems, like Datadog Watchdog or New Relic AI. Personally I use AI tools like Copilot and Claude to write Terraform and scripts faster, explain errors and summarize logs. I always review the output before using it.&lt;/p&gt;

&lt;p&gt;SCRIPTING&lt;/p&gt;

&lt;p&gt;Q: What do you automate with Bash or Python?&lt;br&gt;
A: Cleanup of old images and snapshots, health checks, log parsing, reports for cost or unused resources, small tools with boto3 for AWS tasks.&lt;/p&gt;

&lt;p&gt;Q: Example Python with boto3?&lt;br&gt;
A: A script that lists EC2 instances without an owner tag or stopped for more than 30 days and sends a report, so we can clean up and save cost.&lt;/p&gt;

&lt;p&gt;SALESFORCE&lt;/p&gt;

&lt;p&gt;Q: How would you support DevOps for Salesforce?&lt;br&gt;
A: Keep Salesforce metadata in Git, use Salesforce CLI in GitHub Actions to validate and deploy to sandboxes, run Apex tests, then deploy to production with approval. Tools like Copado or Gearset also exist. I am honest that my Salesforce experience is limited, but the CI/CD ideas are the same.&lt;/p&gt;

&lt;p&gt;SCENARIO AND TROUBLESHOOTING QUESTIONS&lt;/p&gt;

&lt;p&gt;Q: Website is slow in production, what do you do?&lt;br&gt;
A: Check dashboards first, latency, error rate, CPU, memory. Check what changed recently, a deployment or config. Look at traces to find the slow service or database query. Check RDS performance and connections. If a recent deployment caused it, roll back first, then investigate.&lt;/p&gt;

&lt;p&gt;Q: Deployment worked in dev but fails in prod?&lt;br&gt;
A: Compare config, secrets, IAM permissions, resource limits, network rules and data. Usually it is a missing secret, permission or different environment variable.&lt;/p&gt;

&lt;p&gt;Q: A node in EKS is NotReady?&lt;br&gt;
A: Describe the node, check disk pressure, memory pressure, kubelet logs, network plugin. Cordon and drain it, and let the node group replace it.&lt;/p&gt;

&lt;p&gt;Q: Traffic spike during exam registration, how do you prepare?&lt;br&gt;
A: Load test before, set HPA and cluster autoscaling, scale RDS or use read replicas, add caching and CDN with CloudFront, set alerts, and have the team ready on call that day.&lt;/p&gt;

&lt;p&gt;Q: Someone deleted a production resource by mistake?&lt;br&gt;
A: Restore from backup or snapshot, recreate with Terraform. Then prevent it with prevent_destroy, limited access, and reviews.&lt;/p&gt;

&lt;p&gt;Q: How do you do disaster recovery?&lt;br&gt;
A: Define RTO and RPO with business. Backups with AWS Backup, cross region copies, infrastructure as code so we can rebuild fast, and test the restore regularly.&lt;/p&gt;

&lt;p&gt;BEHAVIORAL QUESTIONS&lt;/p&gt;

&lt;p&gt;Q: Tell me about a production incident you handled.&lt;br&gt;
A: An app started returning errors after a deployment. I joined the call, saw the error rate in Grafana, and found a new release used a wrong secret name. We rolled back with Argo CD in a few minutes. After, I added a check in the pipeline and wrote root cause analysis so it would not happen again.&lt;/p&gt;

&lt;p&gt;Q: Tell me about a time you disagreed with a teammate.&lt;br&gt;
A: A developer wanted direct kubectl access in prod to fix things fast. I explained the risk, and we agreed on GitOps plus a break glass process for emergencies. We both got what we needed, speed and safety.&lt;/p&gt;

&lt;p&gt;Q: How do you mentor junior engineers?&lt;br&gt;
A: Pair work, give small real tasks, code reviews with explanation, and good documentation. I let them own something so they grow confidence.&lt;/p&gt;

&lt;p&gt;Q: Tell me about a tool or process you introduced.&lt;br&gt;
A: Argo CD and GitOps. I started with a pilot team, showed results, wrote guides, did demos, and helped teams move one by one. Most teams moved within a few months.&lt;/p&gt;

&lt;p&gt;Q: How do you handle many priorities?&lt;br&gt;
A: Production issues first, then things blocking other teams, then planned work. I talk with my manager when priorities conflict.&lt;/p&gt;

&lt;p&gt;Q: Why are you leaving or why this role?&lt;br&gt;
A: I want a senior role with more ownership, platform engineering and mentoring, and a mission I care about. SOA is a strong organization in Chicago and the Salesforce migration is a great challenge.&lt;/p&gt;

&lt;p&gt;GAPS AND HOW TO ANSWER HONESTLY&lt;/p&gt;

&lt;p&gt;Azure and Azure DevOps: main experience is AWS, but the concepts are the same, I can learn fast.&lt;br&gt;
New Relic and Splunk: used Datadog and Prometheus, same ideas.&lt;br&gt;
PagerDuty and Opsgenie: say what you used for alerting and on call, same process.&lt;br&gt;
HashiCorp Vault: used AWS Secrets Manager, same purpose.&lt;br&gt;
Okta or Azure AD: understand SSO and federation with SAML and OIDC.&lt;br&gt;
Salesforce: limited, but understand CI/CD for it.&lt;br&gt;
Never say I do not know only. Say I have not used that exact tool, but I used this similar one, and here is how I would approach it.&lt;/p&gt;

&lt;p&gt;QUESTIONS TO ASK THEM&lt;/p&gt;

&lt;p&gt;What does success look like in the first 90 days?&lt;br&gt;
Is your main cloud AWS, Azure, or both?&lt;br&gt;
Do you use GitHub Actions or Azure DevOps today?&lt;br&gt;
How do you deploy Salesforce changes now?&lt;br&gt;
Are you running Kubernetes today, or mostly VMs?&lt;br&gt;
Do you have SLOs and on call set up, and which tools?&lt;br&gt;
How does DevOps work with the cybersecurity and quality engineering teams?&lt;br&gt;
How are you using AI tools today?&lt;br&gt;
What is the biggest pain point right now?&lt;br&gt;
What are the next steps in the process?&lt;/p&gt;

&lt;p&gt;Good luck, you are well prepared.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>career</category>
      <category>devops</category>
      <category>interview</category>
    </item>
    <item>
      <title>interview questions and answers based on real interview for Jibek</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Mon, 02 Nov 2026 21:59:48 +0000</pubDate>
      <link>https://dev.to/jumptotech/interview-questions-and-answers-based-on-real-interview-for-jibek-kff</link>
      <guid>https://dev.to/jumptotech/interview-questions-and-answers-based-on-real-interview-for-jibek-kff</guid>
      <description>&lt;p&gt;TELL ME ABOUT YOURSELF&lt;/p&gt;

&lt;p&gt;My name is Zhibek. I am a DevOps Engineer with more than 5 years of experience in AWS cloud. I started at Yelp in 2021, where I worked 4 years on high traffic consumer apps. I built AWS infrastructure, ran Kubernetes on EKS, and improved our CI CD pipelines with GitHub Actions. With blue green deployments and automatic rollback, I made deployments 35 percent faster. I also mentored junior engineers and wrote runbooks for the team. Now I work at Zulily, where I build Terraform for dev, staging and production, run EKS with autoscaling, and build secure pipelines with approval steps. I have AWS Solutions Architect Associate and CKAD certifications. Now I am ready for the next step, to lead a team as a player coach, and that is why this role at Herc Rentals is very interesting for me.&lt;/p&gt;

&lt;p&gt;DAY TO DAY RESPONSIBILITIES&lt;/p&gt;

&lt;p&gt;My day starts with checking CloudWatch dashboards and alerts to see if anything broke at night. Then we have a standup with the team. Most of the day I work on Terraform changes, like new environments, network changes or new services. I review pull requests from other engineers. I help developers when their pipeline fails or their app does not scale well on EKS. I fix production issues when they happen and do root cause analysis after. I also update documents and runbooks so the team knows how to handle things. Sometimes I meet with security or app teams to plan new projects.&lt;/p&gt;

&lt;p&gt;TELL ME ABOUT YOUR PROJECT&lt;/p&gt;

&lt;p&gt;At Zulily the team needed a private database that is easy to repeat in all environments. I wrote Terraform modules for Amazon DocumentDB, put it in private subnets, and used security groups and IAM so only approved apps on EKS can connect. I added it to GitHub Actions with plan, review and approval before production. I set CloudWatch alarms for CPU, connections and storage. The result was the same setup in dev, staging and production, no public access, and new environments now are built much faster.&lt;/p&gt;

&lt;p&gt;Second project if they ask, at Yelp. Deployments were slow and risky. I optimized GitHub Actions with caching and parallel jobs, added blue green deployments, and added automatic rollback if health checks fail. Deployments became 35 percent faster and we had fewer failed releases.&lt;/p&gt;

&lt;p&gt;TECHNICAL QUESTIONS AND SHORT ANSWERS&lt;/p&gt;

&lt;p&gt;What is Terraform state and why remote state&lt;br&gt;
State is a file where Terraform keeps what it created. I keep it in S3 so the whole team uses the same state, and DynamoDB locks it so two people cannot change at the same time.&lt;/p&gt;

&lt;p&gt;How do you structure Terraform for many environments&lt;br&gt;
I use reusable modules and separate folders or workspaces for dev, staging and production, with different variable files. Same code, different values.&lt;/p&gt;

&lt;p&gt;What is Terraform drift and how do you handle it&lt;br&gt;
Drift is when someone changes things by hand in the console. I run terraform plan regularly to find it, and then fix it in code, not by hand.&lt;/p&gt;

&lt;p&gt;Terraform vs CloudFormation vs Bicep&lt;br&gt;
CloudFormation is only AWS, Bicep is only Azure, Terraform works on many clouds. For a multi cloud company like Herc, Terraform is the best choice for one standard.&lt;/p&gt;

&lt;p&gt;What is a landing zone&lt;br&gt;
It is a ready secure base for cloud accounts, with account structure, network, IAM, logging and guardrails. In AWS it is Control Tower and Organizations. New teams get a safe account fast.&lt;/p&gt;

&lt;p&gt;How does Kubernetes autoscaling work&lt;br&gt;
HPA adds more pods when CPU or memory is high. Cluster Autoscaler adds more nodes when pods cannot fit. Together they handle traffic changes.&lt;/p&gt;

&lt;p&gt;A pod keeps crashing, what do you do&lt;br&gt;
I run kubectl describe pod and kubectl logs. Common reasons are wrong config, missing secret, out of memory, or failing health checks. Then I fix and redeploy.&lt;/p&gt;

&lt;p&gt;What is Helm&lt;br&gt;
Helm is a package manager for Kubernetes. It uses templates and values files so we deploy the same app to many environments in a standard way.&lt;/p&gt;

&lt;p&gt;Blue green vs canary&lt;br&gt;
Blue green has two full environments and you switch all traffic at once, easy rollback. Canary sends small traffic first to the new version, then more if it is healthy.&lt;/p&gt;

&lt;p&gt;How do you design a CI CD pipeline&lt;br&gt;
Build, unit tests, security scan, terraform plan, approval for production, deploy, health check, and automatic rollback if it fails.&lt;/p&gt;

&lt;p&gt;How do you keep secrets safe in pipelines&lt;br&gt;
Never put secrets in code. Use AWS Secrets Manager or Parameter Store, and GitHub OIDC to get short time AWS credentials instead of long keys.&lt;/p&gt;

&lt;p&gt;Explain VPC design&lt;br&gt;
Public subnets for load balancers, private subnets for apps and databases, NAT gateway for outbound internet, security groups to control traffic, many availability zones for high availability.&lt;/p&gt;

&lt;p&gt;Security group vs NACL&lt;br&gt;
Security group works on instance level and is stateful. NACL works on subnet level and is stateless, so you need rules both ways.&lt;/p&gt;

&lt;p&gt;What is hybrid connectivity&lt;br&gt;
Connecting on premise data center to the cloud with Site to Site VPN or Direct Connect in AWS, ExpressRoute in Azure, FastConnect in OCI. Transit Gateway helps connect many VPCs.&lt;/p&gt;

&lt;p&gt;What is IAM least privilege&lt;br&gt;
Give only the permissions needed, nothing more. Use roles, not users with long keys, and review permissions often.&lt;/p&gt;

&lt;p&gt;How do you do disaster recovery&lt;br&gt;
First know RTO and RPO, how fast to recover and how much data you can lose. Then backups, multi AZ, cross region copies, and test the recovery regularly, not only on paper.&lt;/p&gt;

&lt;p&gt;How do you reduce cloud cost&lt;br&gt;
Right size instances, autoscaling, Savings Plans or Reserved Instances, spot for non critical work, delete unused resources, tagging for each team, and monthly cost reports to leadership.&lt;/p&gt;

&lt;p&gt;How do you handle a production outage&lt;br&gt;
First stop the impact, maybe rollback. Communicate to stakeholders. Find root cause with logs and metrics. After that write a postmortem with no blame and fix so it does not happen again.&lt;/p&gt;

&lt;p&gt;Do you have Azure or OCI experience&lt;br&gt;
Be honest. My deep experience is AWS, but the concepts are the same. VPC is VNet, IAM is Entra ID and RBAC, EKS is AKS or OKE. Terraform works on all of them, so I can learn fast. I already started learning Azure basics.&lt;/p&gt;

&lt;p&gt;How do you use AI in your work&lt;br&gt;
I use Claude AI to help draft pipelines, review Terraform and write documentation. I always review and test before using it. I think AI can help the team move faster when used carefully.&lt;/p&gt;

&lt;p&gt;MANAGER QUESTIONS&lt;/p&gt;

&lt;p&gt;How do you handle a low performer&lt;br&gt;
Talk early in one on one, understand the reason, set clear goals with time, give support, and follow up. If no change, work with HR.&lt;/p&gt;

&lt;p&gt;How do you prioritize when everything is urgent&lt;br&gt;
Production issues and security first, then business priorities agreed with leadership. I make the work visible so everyone sees the tradeoffs.&lt;/p&gt;

&lt;p&gt;How do you manage contractors&lt;br&gt;
Clear scope, same standards and code review as full time, and documentation so knowledge stays in the company.&lt;/p&gt;

&lt;p&gt;Two engineers disagree on a design, what do you do&lt;br&gt;
Let both explain, compare by facts like cost, risk and simplicity, maybe do a small test, then decide and move forward together.&lt;/p&gt;

&lt;p&gt;What will you do in first 90 days&lt;br&gt;
First 30 days listen and learn the team, systems and pain points. Next 30 days find quick wins like standards and runbooks. Last 30 days make a roadmap with leadership.&lt;/p&gt;

&lt;p&gt;How do you measure team success&lt;br&gt;
Deployment frequency, failed changes, time to recover, uptime, cloud cost, and team happiness.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>career</category>
      <category>devops</category>
      <category>interview</category>
    </item>
    <item>
      <title>2-2 The Midnight Payment Processing Incident — Kubernetes, PostgreSQL, Terraform, CI/CD, Grafana and PagerDuty</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Fri, 30 Oct 2026 02:04:16 +0000</pubDate>
      <link>https://dev.to/jumptotech/2-2-the-midnight-payment-processing-incident-kubernetes-postgresql-terraform-cicd-grafana-33a5</link>
      <guid>https://dev.to/jumptotech/2-2-the-midnight-payment-processing-incident-kubernetes-postgresql-terraform-cicd-grafana-33a5</guid>
      <description>&lt;p&gt;Student hands-on guide · 3 classes × 3 hours · AWS EKS training environment&lt;/p&gt;

&lt;h3&gt;
  
  
  Your mission
&lt;/h3&gt;

&lt;p&gt;You are a DevOps/SRE engineer supporting a banking payment-processing platform. At midnight, PagerDuty notifies the primary on-call engineer that payment transactions are failing.&lt;/p&gt;

&lt;p&gt;You open Grafana and see increasing HTTP 503 errors. But when you inspect Kubernetes, the application Pods are all &lt;code&gt;Running&lt;/code&gt; and &lt;code&gt;Ready&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How can the application be healthy according to Kubernetes while customers cannot complete payments?&lt;/p&gt;

&lt;p&gt;You will investigate the application, its PostgreSQL database, Kubernetes networking, deployment history, monitoring, and the infrastructure changes that could have caused the incident.&lt;/p&gt;

&lt;p&gt;This is a realistic fictional production case study, supported by a real, runnable training lab. You must not claim that it is an actual incident at a named bank.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Incident ticket
&lt;/h2&gt;

&lt;p&gt;INC-2026-1047&lt;/p&gt;

&lt;p&gt;SEV-1 · Scenario&lt;/p&gt;

&lt;p&gt;Payment Processing API — Elevated 5xx Error Rate&lt;/p&gt;

&lt;p&gt;PagerDuty · Payments Production · 12:05 AM&lt;/p&gt;

&lt;p&gt;Reported impact: Payment submissions failing across the customer-facing banking application.&lt;/p&gt;

&lt;p&gt;Monitoring: HTTP 503 responses increasing, payment success rate declining, API Pods still Ready.&lt;/p&gt;

&lt;p&gt;Initial hypothesis: Application dependency failure, database connectivity, or recent infrastructure change.&lt;/p&gt;

&lt;p&gt;Assigned: Primary On-Call SRE&lt;/p&gt;

&lt;p&gt;Escalation: Incident Commander, Backend Engineering, DBA, Cloud Platform, Release Engineering, Security.&lt;/p&gt;

&lt;p&gt;In the hypothetical production architecture, the application runs on AWS EKS across three Availability Zones and connects to Amazon RDS PostgreSQL. Terraform manages security groups and networking; GitHub Actions handles application and infrastructure pipelines.&lt;/p&gt;

&lt;p&gt;For the actual student lab, we use two Payment API replicas and PostgreSQL inside Kubernetes to keep costs and resource requirements low.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Production architecture and team responsibilities
&lt;/h2&gt;

&lt;p&gt;Reference production architecture. The classroom lab replaces RDS and AWS security-group failure with an in-cluster database and NetworkPolicy.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Team&lt;/th&gt;
&lt;th&gt;Responsibility during incident&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary On-Call SRE&lt;/td&gt;
&lt;td&gt;Acknowledge alert, assess impact, investigate, mitigate and communicate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incident Commander&lt;/td&gt;
&lt;td&gt;Coordinate teams, severity, updates and escalation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend/Application Team&lt;/td&gt;
&lt;td&gt;Investigate application errors, connection pooling, configuration and code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database Administrator&lt;/td&gt;
&lt;td&gt;Check database availability, active connections, locks, CPU, I/O and query performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud/Platform Team&lt;/td&gt;
&lt;td&gt;Investigate EKS, VPC, security groups, routing and network policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release/CI/CD Team&lt;/td&gt;
&lt;td&gt;Check recent releases, GitHub Actions workflows and Terraform changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security Team&lt;/td&gt;
&lt;td&gt;Review and approve necessary access-rule changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A primary on-call engineer may initially perform several of these functions, especially on a small team. Do not wait for a meeting before checking the impact and following your incident-response runbook.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. What you will build
&lt;/h2&gt;

&lt;p&gt;The lab creates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Namespace &lt;code&gt;payments-incident-lab&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;PostgreSQL database with a &lt;code&gt;simulated_payments&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;Python Payment API with two replicas&lt;/li&gt;
&lt;li&gt;Kubernetes Services and health probes&lt;/li&gt;
&lt;li&gt;Prometheus metrics for requests, errors and latency&lt;/li&gt;
&lt;li&gt;A controlled database connectivity incident&lt;/li&gt;
&lt;li&gt;Recovery and verification procedures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The lab uses synthetic payments only. It does not charge cards or connect to real payment processors.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Requirements
&lt;/h2&gt;

&lt;p&gt;You need a training EKS cluster, working &lt;code&gt;kubectl&lt;/code&gt;, Docker with permission to push images to a registry, and enough capacity for three small Pods in addition to monitoring.&lt;/p&gt;

&lt;p&gt;For the NetworkPolicy incident, the cluster must have NetworkPolicy enforcement enabled. Installing a NetworkPolicy resource without an enforcing CNI will not necessarily block traffic.&lt;/p&gt;

&lt;h3&gt;
  
  
  First, verify your environment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl config current-context
kubectl get nodes &lt;span class="nt"&gt;-o&lt;/span&gt; wide
kubectl get namespaces
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring
kubectl get storageclass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not perform this exercise in a real production namespace.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part A — Create all application and Kubernetes files
&lt;/h1&gt;

&lt;p&gt;Create the project folders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; payment-incident-lab/&lt;span class="o"&gt;{&lt;/span&gt;app,k8s,scripts,grafana,terraform&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;payment-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File 1 — &lt;code&gt;app/requirements.txt&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flask==3.1.1
psycopg[binary]==3.2.9
prometheus-client==0.22.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File 2 — &lt;code&gt;app/app.py&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is the application students will troubleshoot. Notice that &lt;code&gt;/readyz&lt;/code&gt; checks the application process, but deliberately does not check database connectivity. This allows Pods to remain Ready while payment requests fail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                    &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                    &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;            &lt;span class="n"&gt;REQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/db-check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;200&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reachable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;            &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;database connectivity failed: %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;            &lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="n"&gt;DB_ERRORS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;            &lt;span class="n"&gt;REQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/db-check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;503&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;database_unavailable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/payments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;DURATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/payments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;silent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Idempotency-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;        &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;            &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;            &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;            &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount_cents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount_cents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount_cents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;        &lt;span class="p"&gt;):&lt;/span&gt;            &lt;span class="n"&gt;REQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/payments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;400&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;                &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Idempotency-Key and integer &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;                      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount_cents 1..100000 required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;            &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                    &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;                        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;                        INSERT INTO simulated_payments                        (idempotency_key, amount_cents)                        VALUES (%s, %s)                        ON CONFLICT (idempotency_key)                        DO NOTHING                        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount_cents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;                    &lt;span class="p"&gt;)&lt;/span&gt;                    &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;                        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;                        SELECT id, amount_cents, status                        FROM simulated_payments                        WHERE idempotency_key = %s                        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt;                    &lt;span class="p"&gt;)&lt;/span&gt;                    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File 3 — &lt;code&gt;app/Dockerfile&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.12-slim&lt;/span&gt;

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

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; app.py .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;--uid&lt;/span&gt; 10001 &lt;span class="nt"&gt;--create-home&lt;/span&gt; appuser

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; 10001&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python", "app.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File 4 — &lt;code&gt;k8s/00-namespace.yaml&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File 5 — &lt;code&gt;k8s/01-postgres.yaml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This database is disposable. Its storage uses &lt;code&gt;emptyDir&lt;/code&gt;, so deleting or replacing the database Pod can destroy its data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-auth&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;classroom-only-not-production&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-init&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;001-init.sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;CREATE TABLE IF NOT EXISTS simulated_payments (&lt;/span&gt;
      &lt;span class="s"&gt;id BIGSERIAL PRIMARY KEY,&lt;/span&gt;
      &lt;span class="s"&gt;idempotency_key TEXT NOT NULL UNIQUE,&lt;/span&gt;
      &lt;span class="s"&gt;amount_cents INTEGER NOT NULL&lt;/span&gt;
        &lt;span class="s"&gt;CHECK (amount_cents &amp;gt; 0),&lt;/span&gt;
      &lt;span class="s"&gt;status TEXT NOT NULL&lt;/span&gt;
        &lt;span class="s"&gt;DEFAULT 'simulated_approved',&lt;/span&gt;
      &lt;span class="s"&gt;created_at TIMESTAMPTZ NOT NULL DEFAULT now()&lt;/span&gt;
    &lt;span class="s"&gt;);&lt;/span&gt;
&lt;span class="s"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Recreate&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;labuser&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-auth&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;init&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/docker-entrypoint-initdb.d&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;data&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/postgresql/data&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sh&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;-c&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pg_isready -U labuser -d payments&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;50m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;128Mi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;512Mi&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;init&lt;/span&gt;
          &lt;span class="na"&gt;configMap&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-init&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;data&lt;/span&gt;
          &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File 6 — &lt;code&gt;k8s/02-payment-api.yaml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Replace &lt;code&gt;REPLACE_WITH_YOUR_IMAGE&lt;/code&gt; with the container image you build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
    &lt;span class="na"&gt;rollingUpdate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;maxSurge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;maxUnavailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-api&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-api&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-api&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REPLACE_WITH_YOUR_IMAGE&lt;/span&gt;
          &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Always&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
              &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_HOST&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_NAME&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_USER&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;labuser&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DB_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-auth&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/readyz&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/healthz&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;50m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;64Mi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;256Mi&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-api&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-api&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File 7 — &lt;code&gt;k8s/03-networkpolicy-outage.yaml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is the controlled failure. It blocks new incoming connections to the PostgreSQL Pod from the API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;block-postgres-ingress&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important: This only works when your cluster enforces Kubernetes NetworkPolicy. On EKS, check the Amazon VPC CNI NetworkPolicy configuration before running this exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  File 8 — &lt;code&gt;k8s/04-servicemonitor-optional.yaml&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monitoring.coreos.com/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceMonitor&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;namespaceSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchNames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-api&lt;/span&gt;
  &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/metrics&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;release: monitoring&lt;/code&gt; label must match the selector of your Prometheus installation. This file requires the Prometheus Operator ServiceMonitor CRD.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part B — Build, deploy and verify
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 1. Build and push the Docker image
&lt;/h2&gt;

&lt;p&gt;Run from inside &lt;code&gt;payment-incident-lab&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Replace the Docker Hub username with yours.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'YOUR_DOCKERHUB_USERNAME/jumptotech-payment-api:v1'&lt;/span&gt;

docker buildx build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--push&lt;/span&gt; ./app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your EKS worker nodes are ARM64, use &lt;code&gt;linux/arm64&lt;/code&gt; instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2. Deploy PostgreSQL
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; k8s/00-namespace.yaml

kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; k8s/01-postgres.yaml

kubectl rollout status deployment/lab-postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PostgreSQL Pod should show &lt;code&gt;1/1 Running&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3. Deploy Payment API
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s2"&gt;"s|REPLACE_WITH_YOUR_IMAGE|&lt;/span&gt;&lt;span class="nv"&gt;$IMAGE&lt;/span&gt;&lt;span class="s2"&gt;|"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  k8s/02-payment-api.yaml | kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -

kubectl rollout status deployment/payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180s

kubectl get deployments &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected baseline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME           READY   UP-TO-DATE   AVAILABLE
lab-postgres   1/1     1            1
payment-api    2/2     2            2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4. Verify the database table
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  deployment/lab-postgres &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  psql &lt;span class="nt"&gt;-U&lt;/span&gt; labuser &lt;span class="nt"&gt;-d&lt;/span&gt; payments &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'\dt'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the &lt;code&gt;simulated_payments&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;Check the number of synthetic payments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  deployment/lab-postgres &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  psql &lt;span class="nt"&gt;-U&lt;/span&gt; labuser &lt;span class="nt"&gt;-d&lt;/span&gt; payments &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'SELECT COUNT(*) FROM simulated_payments;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5. Test the application
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;scripts/02-smoke-test.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;NS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;payments-incident-lab

kubectl run &lt;span class="s2"&gt;"smoke-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curlimages/curl:8.11.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--command&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'
    echo "READINESS:"
    curl -sS -i --max-time 10 \
      http://payment-api:8080/readyz

    echo
    echo "DB CHECK:"
    curl -sS -i --max-time 10 \
      http://payment-api:8080/api/db-check

    echo
    echo "SYNTHETIC PAYMENT:"
    curl -sS -i --max-time 10 \
      -X POST \
      http://payment-api:8080/api/payments \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: classroom-$(date +%s)" \
      -d "{\"amount_cents\":1250}"
'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash scripts/02-smoke-test.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Expected HTTP status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/readyz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/api/db-check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/api/payments&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The temporary curl Pod may display an attach warning after completing its request. Focus on the actual HTTP response.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part C — Configure Grafana and Prometheus
&lt;/h1&gt;

&lt;p&gt;First verify the monitoring components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring

kubectl get crd servicemonitors.monitoring.coreos.com

kubectl get prometheus &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect the ServiceMonitor selectors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get prometheus &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A12&lt;/span&gt; serviceMonitorSelector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the ServiceMonitor label matches your Prometheus configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; k8s/04-servicemonitor-optional.yaml

kubectl get servicemonitor &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Grafana, select your Prometheus data source and create the following panels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Panel 1 — Payment API request rate by HTTP status
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="nf"&gt;sum&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment_http_requests_total&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This distinguishes successful requests from HTTP 400, 409 and 503 responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Panel 2 — HTTP 5xx error rate
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment_http_requests_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=~&lt;/span&gt;&lt;span class="s2"&gt;"5.."&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Panel 3 — Database errors over five minutes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;increase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment_db_errors_total&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Panel 4 — Available replicas
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;kube_deployment_status_replicas_available&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payments-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payment-api"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Panel 5 — Desired replicas
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;kube_deployment_spec_replicas&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payments-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payment-api"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Panel 6 — Pod readiness
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="nf"&gt;sum&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;kube_pod_status_ready&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payments-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="na"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;=~&lt;/span&gt;&lt;span class="s2"&gt;"payment-api-.*"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Panel 7 — Payment request p95 latency
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="nb"&gt;histogram_quantile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;sum&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;le&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;payment_http_request_duration_seconds_bucket&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;        &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/api/payments"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;      &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate test traffic before expecting request metrics to appear. Check that Prometheus is actually scraping the Payment API target. The metrics may remain absent if the ServiceMonitor selector is incorrect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key learning point
&lt;/h3&gt;

&lt;p&gt;A dashboard can show:&lt;/p&gt;

&lt;p&gt;Available Pods&lt;/p&gt;

&lt;h1&gt;
  
  
  2 / 2
&lt;/h1&gt;

&lt;p&gt;Kubernetes sees healthy processes&lt;/p&gt;

&lt;p&gt;Payment API&lt;/p&gt;

&lt;h1&gt;
  
  
  503
&lt;/h1&gt;

&lt;p&gt;Database-dependent requests fail&lt;/p&gt;

&lt;p&gt;This is not contradictory. Kubernetes readiness and application business functionality are different signals.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part D — Create the incident
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Class 2: Midnight outage simulation
&lt;/h2&gt;

&lt;p&gt;Your instructor announces:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is 12:05 AM. PagerDuty has triggered a critical alert. Customers cannot complete payment transactions. Grafana shows elevated HTTP 503 errors, but all Payment API Pods appear healthy. You are the primary on-call engineer. Investigate the incident and identify the failing dependency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 1. Confirm the healthy baseline
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

bash scripts/02-smoke-test.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not continue until the database check and payment request return HTTP 200.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2. Introduce the controlled failure
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;scripts/03-inject-outage.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; k8s/03-networkpolicy-outage.yaml

kubectl get networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'\nRun the smoke test and investigate.\n'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash scripts/03-inject-outage.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash scripts/02-smoke-test.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When NetworkPolicy enforcement is active, expected behavior is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Payment API Pods&lt;/td&gt;
&lt;td&gt;Running, Ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL Pod&lt;/td&gt;
&lt;td&gt;Running, Ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API readiness endpoint&lt;/td&gt;
&lt;td&gt;HTTP 200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database connectivity endpoint&lt;/td&gt;
&lt;td&gt;HTTP 503&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Synthetic payment request&lt;/td&gt;
&lt;td&gt;HTTP 503&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application logs&lt;/td&gt;
&lt;td&gt;Database connectivity errors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If requests still succeed, verify that NetworkPolicy enforcement is enabled. Do not assume the incident is active simply because &lt;code&gt;kubectl apply&lt;/code&gt; succeeded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3. Investigate the incident
&lt;/h2&gt;

&lt;p&gt;Start with the Kubernetes resources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="nt"&gt;-o&lt;/span&gt; wide

kubectl get deployments &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl get endpointslices &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect the API Deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe deployment payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect the API Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pods &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect application logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs deployment/payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-log-requests&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for errors indicating the application cannot communicate with PostgreSQL.&lt;/p&gt;

&lt;p&gt;Inspect the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lab-postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl logs deployment/lab-postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the NetworkPolicies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl describe networkpolicy block-postgres-ingress &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl get networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check rollout history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deployment/payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl rollout status deployment/payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important: In this particular incident, the API Deployment may have had no recent rollout at all. The problem is a networking configuration change, not necessarily a new container version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Student investigation script
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;scripts/04-investigate.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;NS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;payments-incident-lab

kubectl get pods,deploy,svc,endpointslices &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

kubectl describe deployment payment-api &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

kubectl logs deployment/payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-log-requests&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10

kubectl get networkpolicy &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; yaml

kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deployment/payment-api &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash scripts/04-investigate.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Root-cause analysis
&lt;/h3&gt;

&lt;p&gt;In this lab, the NetworkPolicy selects the PostgreSQL Pod and allows no incoming traffic. The application can still start and answer &lt;code&gt;/readyz&lt;/code&gt;, but new PostgreSQL connections fail.&lt;/p&gt;

&lt;p&gt;The root cause is therefore database connectivity blocked by Kubernetes NetworkPolicy, not a crashed application Pod.&lt;/p&gt;

&lt;p&gt;A blind &lt;code&gt;kubectl rollout undo&lt;/code&gt; of the Payment API is not an appropriate fix because the network policy would remain in effect.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part E — Restore service
&lt;/h1&gt;

&lt;p&gt;After identifying the policy and following the classroom change procedure, remove the offending rule.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete networkpolicy block-postgres-ingress &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that the application is still available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl rollout status deployment/payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;120s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the payment tests again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash scripts/02-smoke-test.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the database contains the successful synthetic payments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  deployment/lab-postgres &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  psql &lt;span class="nt"&gt;-U&lt;/span&gt; labuser &lt;span class="nt"&gt;-d&lt;/span&gt; payments &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'SELECT id, amount_cents, status, created_at
      FROM simulated_payments
      ORDER BY id DESC
      LIMIT 10;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;scripts/05-recover.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

kubectl delete networkpolicy block-postgres-ingress &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ignore-not-found&lt;/span&gt;

kubectl rollout status deployment/payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;120s

bash scripts/02-smoke-test.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash scripts/05-recover.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recovery is verified when new database checks and synthetic payment requests succeed. In a real payment system, the application and database teams would also need to verify transaction integrity, retries and reconciliation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part F — Terraform and AWS RDS investigation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Why Terraform matters
&lt;/h2&gt;

&lt;p&gt;In a production environment, PostgreSQL may run on Amazon RDS rather than inside Kubernetes.&lt;/p&gt;

&lt;p&gt;Suppose a GitHub Actions workflow applies a Terraform change that accidentally removes the security-group rule allowing the EKS application to reach RDS on TCP port 5432.&lt;/p&gt;

&lt;p&gt;The symptoms could resemble our lab: Kubernetes Pods are Ready, but application requests fail because database connections cannot be established.&lt;/p&gt;

&lt;p&gt;The two failure mechanisms are different:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Classroom lab&lt;/th&gt;
&lt;th&gt;Production reference scenario&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes NetworkPolicy blocks PostgreSQL ingress&lt;/td&gt;
&lt;td&gt;AWS security group blocks EKS-to-RDS traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL runs inside EKS&lt;/td&gt;
&lt;td&gt;PostgreSQL runs on Amazon RDS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fix the Kubernetes NetworkPolicy&lt;/td&gt;
&lt;td&gt;Restore the correct AWS security-group rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Investigate &lt;code&gt;kubectl get networkpolicy&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Investigate AWS VPC, security groups, CloudTrail and Terraform changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  File 9 — &lt;code&gt;terraform/EXAMPLE_ONLY.tf&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is a teaching example. Do not run &lt;code&gt;terraform apply&lt;/code&gt; on this file against an existing AWS environment. The correct security group and identity must first be established.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"rds_security_group_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"approved_eks_application_security_group_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc_security_group_ingress_rule"&lt;/span&gt; &lt;span class="s2"&gt;"postgres_from_eks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;security_group_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rds_security_group_id&lt;/span&gt;

  &lt;span class="nx"&gt;referenced_security_group_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;approved_eks_application_security_group_id&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;ip_protocol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;

  &lt;span class="nx"&gt;from_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;

  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Approved EKS application traffic to PostgreSQL"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Terraform investigation commands
&lt;/h3&gt;

&lt;p&gt;For an actual managed Terraform project, first identify the correct repository, workspace, state and pipeline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform version

terraform workspace show

terraform state list

terraform plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review the plan and the last GitHub Actions run. Determine whether a rule was removed, replaced, or changed.&lt;/p&gt;

&lt;p&gt;Do not assume that the latest Terraform deployment caused the incident merely because it happened recently. Correlate the change timestamp with application errors, RDS connection failures, AWS configuration history and network evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI/CD investigation
&lt;/h2&gt;

&lt;p&gt;Students should be able to explain this workflow:&lt;/p&gt;

&lt;p&gt;Developer creates pull request&lt;/p&gt;

&lt;p&gt;GitHub Actions: test, build, security checks&lt;/p&gt;

&lt;p&gt;Terraform fmt, validate, plan and review&lt;/p&gt;

&lt;p&gt;Approved infrastructure change&lt;/p&gt;

&lt;p&gt;Application deployment and post-deploy tests&lt;/p&gt;

&lt;p&gt;Prometheus / Grafana validation and alerting&lt;/p&gt;

&lt;p&gt;An important production lesson: a pipeline can finish successfully while the system is broken. Successful execution of &lt;code&gt;terraform apply&lt;/code&gt; only proves Terraform applied the requested changes; it does not prove payment processing still works.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part G — Three-class teaching schedule
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Duration&lt;/th&gt;
&lt;th&gt;Activities&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Class 1&lt;/td&gt;
&lt;td&gt;3 hours&lt;/td&gt;
&lt;td&gt;Architecture, team roles, Docker, PostgreSQL, EKS Deployment, Services, API testing, Grafana&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Class 2&lt;/td&gt;
&lt;td&gt;3 hours&lt;/td&gt;
&lt;td&gt;PagerDuty ticket, incident injection, logs, database investigation, NetworkPolicy, Terraform and CI/CD analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Class 3&lt;/td&gt;
&lt;td&gt;3 hours&lt;/td&gt;
&lt;td&gt;Recovery, verification, incident report, prevention, mock interview and follow-up questions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Class 1 — Build the platform
&lt;/h2&gt;

&lt;p&gt;Students must finish with a working Payment API, two healthy replicas, PostgreSQL connectivity, successful synthetic payments and visible metrics.&lt;/p&gt;

&lt;p&gt;Instructor questions: What is the difference between a Deployment and a Service? Why do we use a Secret? What does a readiness probe check? How does the API connect to PostgreSQL? Why might database availability differ from Pod readiness?&lt;/p&gt;

&lt;h2&gt;
  
  
  Class 2 — Investigate the outage
&lt;/h2&gt;

&lt;p&gt;Do not immediately tell students the root cause. Present the incident ticket and ask them to gather evidence.&lt;/p&gt;

&lt;p&gt;Students should identify that the Pods are Ready, the database Pod is running, the API reports database connectivity errors, and a NetworkPolicy is blocking the connection.&lt;/p&gt;

&lt;p&gt;Instructor questions: Is this an application crash? Why are there no container restarts? Why does the HTTP 503 error appear? Why would restarting the Pods not fix the problem? What evidence would connect this to a Terraform change in AWS?&lt;/p&gt;

&lt;h2&gt;
  
  
  Class 3 — Recover and explain
&lt;/h2&gt;

&lt;p&gt;Students must explain the root cause, restore connectivity, validate synthetic payments, review Grafana, and present an incident report.&lt;/p&gt;

&lt;p&gt;They should distinguish between mitigation (restoring service), root cause (identifying the failing rule), and prevention (adding change controls and connectivity tests).&lt;/p&gt;

&lt;h1&gt;
  
  
  Part H — Interview preparation
&lt;/h1&gt;

&lt;p&gt;These are the questions students should practice aloud, with technically accurate answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Your Pods are Running and Ready, but customers receive HTTP 503. What do you investigate?
&lt;/h3&gt;

&lt;p&gt;Sample answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would first assess the customer impact using Grafana or another monitoring tool. I would check the HTTP 5xx error rate, latency, and affected endpoints. Then I would inspect the Kubernetes Deployments, Pods, Services and application logs. Since the Pods are Ready, I would not assume Kubernetes itself is healthy end to end. I would investigate downstream dependencies such as the database, networking, authentication and external APIs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. How can all Pods be Ready while payment processing is failing?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Kubernetes readiness only checks what the configured readiness probe verifies. If the probe checks only the application process, the Pod can remain Ready even when the database is unreachable. That's why I would also monitor transaction success rates and perform synthetic end-to-end checks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. What would you check first to determine whether the database is the problem?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I would examine the application logs for connection timeouts, authentication failures, connection-pool exhaustion and query errors. Then I would check database health and connectivity. I would also review database metrics such as CPU, memory, connections, I/O and wait events.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. How would you prove that a Terraform change caused the outage?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I would correlate the incident start time with the Terraform pipeline execution. Then I would review the Terraform plan, the applied changes and AWS configuration history. If the change removed a required RDS security-group rule, I would verify that the affected application could no longer reach the database. I would use that evidence to establish causation rather than relying only on timing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5. Would you immediately run &lt;code&gt;kubectl rollout undo&lt;/code&gt;?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Not automatically. I would first determine whether the application deployment caused the failure. If the root cause is a network rule or database configuration, rolling back the application might not help. I would follow the incident runbook and select the safest mitigation supported by the evidence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  6. What is the difference between HTTP 502, 503 and 504?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Common example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;502 Bad Gateway&lt;/td&gt;
&lt;td&gt;Gateway received an invalid response from an upstream server&lt;/td&gt;
&lt;td&gt;Reverse proxy cannot obtain a valid upstream response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;503 Service Unavailable&lt;/td&gt;
&lt;td&gt;Service cannot currently handle the request&lt;/td&gt;
&lt;td&gt;Payment API deliberately returns 503 when database is unavailable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;504 Gateway Timeout&lt;/td&gt;
&lt;td&gt;Gateway did not receive an upstream response in time&lt;/td&gt;
&lt;td&gt;ALB or proxy times out waiting for an application response&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A database timeout does not automatically mean the customer receives 504. In this lab, the application catches the error and explicitly returns 503.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Who would you involve in a SEV-1 incident?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I would follow the company's incident-response procedure. Depending on the impact, I would involve the incident commander, application engineers, database team, platform engineers and release team. I would communicate the symptoms, current impact, evidence collected, and mitigation plan so the teams could work in parallel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  8. How would you investigate a delayed failure after a successful release?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I would compare the release timestamp with the first customer errors and infrastructure changes. I would investigate whether the failure was triggered by connection-pool exhaustion, database load, expired credentials, a scheduled job, network changes or traffic growth. I would also check whether the application had existing connections that continued working temporarily before new connections started failing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  9. What database metrics would you inspect?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I would review CPU utilization, available memory, connection counts, disk I/O, read and write latency, active sessions, slow queries, locks and wait events. I would use those metrics to distinguish between database overload, slow queries, connection exhaustion and network connectivity failures.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  10. What is a database connection pool?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A connection pool maintains reusable database connections so an application doesn't need to establish a new connection for every request. If the pool is exhausted or connections become invalid, requests may wait, time out or fail. I would check active connections, pool utilization, wait time and timeout settings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  11. How would you restore service without creating additional risk?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I would first identify the failing dependency and the last known good configuration. I would coordinate the mitigation through the incident process, restore only the necessary access, and verify recovery using application requests, database checks, monitoring and synthetic transactions. I would avoid broad security-group changes or unnecessary restarts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  12. What would you do after recovery?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I would confirm that error rates and payment success metrics returned to baseline. Then I would document the incident timeline, impact, root cause, mitigation and prevention actions. I would recommend post-deployment database connectivity checks, better dependency monitoring, Terraform plan review and appropriate change approvals.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Part I — Student incident report
&lt;/h1&gt;

&lt;p&gt;Every student must complete this report after Class 3.&lt;/p&gt;

&lt;p&gt;Incident report template&lt;/p&gt;

&lt;p&gt;Incident ID: INC-2026-1047&lt;/p&gt;

&lt;p&gt;Severity: SEV-1 (training scenario)&lt;/p&gt;

&lt;p&gt;Affected service: Payment Processing API&lt;/p&gt;

&lt;p&gt;Detection: PagerDuty / Grafana&lt;/p&gt;

&lt;p&gt;Start time: Record actual lab injection time&lt;/p&gt;

&lt;p&gt;Recovery time: Record actual successful verification time&lt;/p&gt;

&lt;p&gt;Customer impact: Synthetic payment requests failed in the lab; production customer impact is hypothetical&lt;/p&gt;

&lt;p&gt;Observed symptoms: API Pods Ready, database-dependent requests returned HTTP 503&lt;/p&gt;

&lt;p&gt;Root cause: PostgreSQL ingress blocked by Kubernetes NetworkPolicy&lt;/p&gt;

&lt;p&gt;Mitigation: Removed the offending policy in the isolated lab&lt;/p&gt;

&lt;p&gt;Verification: Database checks and synthetic payments returned HTTP 200&lt;/p&gt;

&lt;p&gt;Prevention: Network change reviews, dependency checks, monitoring, and automated connectivity tests&lt;/p&gt;

&lt;p&gt;Evidence: Attach command outputs, relevant logs, Grafana screenshots and the exact configuration change.&lt;/p&gt;

&lt;h2&gt;
  
  
  File 10 — &lt;code&gt;scripts/01-check.sh&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

kubectl get nodes
kubectl get ns
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring

kubectl get pods,deploy,svc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl get networkpolicy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File 11 — &lt;code&gt;scripts/06-cleanup.sh&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Use only after the classes are finished. This deletes the entire training namespace and its synthetic database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'Delete ENTIRE payments-incident-lab namespace? Type DELETE: '&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  answer

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$answer&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"DELETE"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;kubectl delete namespace payments-incident-lab
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Canceled."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To clean up the optional ServiceMonitor separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete servicemonitor payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ignore-not-found&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final student challenge
&lt;/h2&gt;

&lt;p&gt;Your instructor will ask:&lt;/p&gt;

&lt;p&gt;"It is 12:05 AM. Your Payment API has two healthy Pods, PostgreSQL is Running, and your application deployment has not changed. However, payment requests are returning HTTP 503. What are your first actions, how do you identify the root cause, who do you involve, and how do you restore service safely?"&lt;/p&gt;

&lt;p&gt;You must be able to explain the investigation in your own words, demonstrate the relevant commands, identify the exact failed dependency, and verify the recovery.&lt;/p&gt;

&lt;p&gt;Your goal is not to memorize commands. Your goal is to think and communicate like a DevOps/SRE engineer responding to a production incident.&lt;/p&gt;

&lt;p&gt;JumpToTech DevOps Engineering · Practical Incident Response Training&lt;/p&gt;

</description>
    </item>
    <item>
      <title>JumpToTech DevOps Production Incident Lab #2 The Midnight Payment Processing Incident</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Fri, 30 Oct 2026 01:05:13 +0000</pubDate>
      <link>https://dev.to/jumptotech/jumptotech-devops-production-incident-lab-2-the-midnight-payment-processing-incident-575m</link>
      <guid>https://dev.to/jumptotech/jumptotech-devops-production-incident-lab-2-the-midnight-payment-processing-incident-575m</guid>
      <description>&lt;p&gt;Student training handbook | 3 classes × 3 hours | AWS EKS · Terraform · GitHub Actions · PostgreSQL RDS · Prometheus · Grafana · PagerDuty&lt;/p&gt;

&lt;p&gt;Students, welcome to your next production incident investigation.&lt;/p&gt;

&lt;p&gt;In our previous incident, you investigated Kubernetes Pods that became unavailable after a deployment. This time, the challenge is different.&lt;/p&gt;

&lt;p&gt;All Kubernetes Pods are healthy. The deployment succeeded. The application is reachable. But customers cannot complete payments.&lt;/p&gt;

&lt;p&gt;This is the type of scenario that tests whether you understand the entire production system—not just Kubernetes commands.&lt;/p&gt;

&lt;p&gt;You will work as an on-call DevOps/SRE engineer at a fictional enterprise payment platform. The scenario is designed to resemble incidents that could occur in large financial technology companies, banks, and e-commerce organizations. All company details, ticket numbers, figures, and incident events below are fictional training data.&lt;/p&gt;

&lt;p&gt;By the end of three classes, you should be able to investigate a multi-system incident, identify an infrastructure change, coordinate with other engineering teams, restore service safely, explain database connectivity, and defend your decisions during a technical interview.&lt;/p&gt;

&lt;p&gt;INC-2026-1047 — Payment Authorization Failures&lt;/p&gt;

&lt;p&gt;SEV-1&lt;/p&gt;

&lt;p&gt;Payment success rate&lt;/p&gt;

&lt;h1&gt;
  
  
  41%
&lt;/h1&gt;

&lt;p&gt;Baseline: 99.95%&lt;/p&gt;

&lt;p&gt;HTTP 5xx rate&lt;/p&gt;

&lt;h1&gt;
  
  
  37%
&lt;/h1&gt;

&lt;p&gt;On payment API&lt;/p&gt;

&lt;p&gt;Kubernetes Pods&lt;/p&gt;

&lt;h1&gt;
  
  
  12/12
&lt;/h1&gt;

&lt;p&gt;Ready and Running&lt;/p&gt;

&lt;p&gt;Database&lt;/p&gt;

&lt;h1&gt;
  
  
  Available
&lt;/h1&gt;

&lt;p&gt;RDS instance is running&lt;/p&gt;

&lt;p&gt;Incident clue: A Terraform deployment completed approximately 20 minutes before the payment failures began.&lt;/p&gt;

&lt;p&gt;The critical interview question is:&lt;/p&gt;

&lt;p&gt;“If all Kubernetes Pods are healthy and the RDS database is available, why are customers receiving payment failures?”&lt;/p&gt;

&lt;p&gt;You are not allowed to answer, “I would restart the Pods,” without first explaining what evidence justifies that action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your three-class mission
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Duration&lt;/th&gt;
&lt;th&gt;Your objective&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Class 1 — Detection and triage&lt;/td&gt;
&lt;td&gt;3 hours&lt;/td&gt;
&lt;td&gt;Understand the ticket, production architecture, incident roles, and evidence collection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Class 2 — Deep troubleshooting&lt;/td&gt;
&lt;td&gt;3 hours&lt;/td&gt;
&lt;td&gt;Investigate Kubernetes, CI/CD, Terraform, networking, and PostgreSQL; identify the root cause&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Class 3 — Recovery and interviews&lt;/td&gt;
&lt;td&gt;3 hours&lt;/td&gt;
&lt;td&gt;Restore service, verify transactions, complete the postmortem, and pass a mock technical interview&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You will not be given the root cause at the beginning. Your instructor will reveal additional evidence as you progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The company and production environment
&lt;/h2&gt;

&lt;p&gt;You work for NorthStar Payments, a fictional payment technology company processing transactions for online retailers.&lt;/p&gt;

&lt;p&gt;NorthStar provides payment authorization, order management, transaction history, refunds, and customer account services.&lt;/p&gt;

&lt;p&gt;The production system runs on AWS. The platform team manages infrastructure through Terraform, developers deploy applications through GitHub Actions, and SRE engineers monitor the platform using Prometheus, Grafana, CloudWatch, and PagerDuty.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production architecture
&lt;/h3&gt;

&lt;p&gt;Conceptual production architecture. AWS networking and service placement are simplified for training.&lt;/p&gt;

&lt;p&gt;The system has these components:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Responsible team&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Amazon EKS&lt;/td&gt;
&lt;td&gt;Runs containerized services&lt;/td&gt;
&lt;td&gt;Platform / SRE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment API&lt;/td&gt;
&lt;td&gt;Receives and processes payment requests&lt;/td&gt;
&lt;td&gt;Backend application team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment workers&lt;/td&gt;
&lt;td&gt;Process asynchronous events&lt;/td&gt;
&lt;td&gt;Backend application team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon RDS PostgreSQL&lt;/td&gt;
&lt;td&gt;Stores transaction and payment records&lt;/td&gt;
&lt;td&gt;Database / DBA team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Security Groups&lt;/td&gt;
&lt;td&gt;Control permitted network connections&lt;/td&gt;
&lt;td&gt;Cloud platform / security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terraform&lt;/td&gt;
&lt;td&gt;Provisions and changes AWS infrastructure&lt;/td&gt;
&lt;td&gt;Cloud platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;td&gt;Tests and deploys infrastructure and applications&lt;/td&gt;
&lt;td&gt;DevOps / release engineering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prometheus and Grafana&lt;/td&gt;
&lt;td&gt;Collect and visualize service metrics&lt;/td&gt;
&lt;td&gt;SRE / observability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CloudWatch&lt;/td&gt;
&lt;td&gt;AWS infrastructure logs and metrics&lt;/td&gt;
&lt;td&gt;Cloud platform / SRE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PagerDuty&lt;/td&gt;
&lt;td&gt;Routes urgent alerts to on-call responders&lt;/td&gt;
&lt;td&gt;SRE / incident management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jira Service Management&lt;/td&gt;
&lt;td&gt;Tracks incident tickets and investigation&lt;/td&gt;
&lt;td&gt;Service management&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Example workload sizes
&lt;/h3&gt;

&lt;p&gt;For this case study, the production environment has 12 Payment API Pods, 6 background workers, 3 Availability Zones, and one Multi-AZ PostgreSQL RDS deployment. These are illustrative values, not actual figures from any bank.&lt;/p&gt;

&lt;p&gt;The Payment API has a readiness endpoint at &lt;code&gt;/ready&lt;/code&gt;, which checks whether the HTTP process is responsive. It does not check whether the application can reach PostgreSQL. That design choice will become important.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Your production engineering team
&lt;/h2&gt;

&lt;p&gt;An enterprise incident is not normally handled by one engineer working alone. You may be the first person paged, but different teams own different systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Incident response team structure
&lt;/h2&gt;

&lt;p&gt;Incident Commander&lt;/p&gt;

&lt;p&gt;Coordinates response and decisions&lt;/p&gt;

&lt;p&gt;Primary SRE&lt;/p&gt;

&lt;p&gt;Triage, metrics, Kubernetes&lt;/p&gt;

&lt;p&gt;Platform Engineer&lt;/p&gt;

&lt;p&gt;Terraform, VPC, security groups&lt;/p&gt;

&lt;p&gt;Backend Engineer&lt;/p&gt;

&lt;p&gt;Payment API, application logs&lt;/p&gt;

&lt;p&gt;Database Engineer&lt;/p&gt;

&lt;p&gt;RDS, SQL, connection health&lt;/p&gt;

&lt;p&gt;Release Engineer&lt;/p&gt;

&lt;p&gt;CI/CD, change history&lt;/p&gt;

&lt;p&gt;Security Engineer&lt;/p&gt;

&lt;p&gt;Network access, policy review&lt;/p&gt;

&lt;p&gt;Customer support and business stakeholders receive coordinated status updates through the incident communication process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who is responsible for what?
&lt;/h3&gt;

&lt;p&gt;Primary on-call DevOps/SRE engineer — your role&lt;/p&gt;

&lt;p&gt;You acknowledge the alert, establish the initial technical picture, identify impacted components, collect evidence, coordinate with the incident team, and execute approved operational actions within your access and authority.&lt;/p&gt;

&lt;p&gt;Incident Commander&lt;/p&gt;

&lt;p&gt;Owns coordination, severity management, escalation, communications, and ensuring someone is assigned to each workstream. The incident commander does not necessarily perform the technical fix.&lt;/p&gt;

&lt;p&gt;Application engineer&lt;/p&gt;

&lt;p&gt;Investigates payment request failures, database client errors, connection pool behavior, retry logic, and application code.&lt;/p&gt;

&lt;p&gt;Cloud platform engineer&lt;/p&gt;

&lt;p&gt;Investigates AWS networking, Terraform state and plans, security groups, IAM, EKS networking, and infrastructure changes. This engineer normally owns the corrective Terraform pull request.&lt;/p&gt;

&lt;p&gt;Database engineer&lt;/p&gt;

&lt;p&gt;Checks database availability, active connections, PostgreSQL errors, query performance, locks, replication or failover state, and database-side access settings.&lt;/p&gt;

&lt;p&gt;Release engineer&lt;/p&gt;

&lt;p&gt;Finds the GitHub Actions deployment run, commit SHA, pull request, approvers, change window, and any simultaneous releases.&lt;/p&gt;

&lt;p&gt;Security engineer&lt;/p&gt;

&lt;p&gt;Reviews whether a proposed security group change is permitted and ensures recovery does not introduce unnecessary network exposure.&lt;/p&gt;

&lt;p&gt;Customer support and communications&lt;/p&gt;

&lt;p&gt;Collect customer reports and distribute approved incident updates. They should not receive raw database credentials or sensitive customer records.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interview question
&lt;/h3&gt;

&lt;p&gt;“If you are the primary on-call engineer, are you personally responsible for fixing every component?”&lt;/p&gt;

&lt;p&gt;A strong answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I am responsible for responding to the incident, understanding the impact, and driving technical triage within my role. I would engage the correct service owners for specialized components such as RDS, networking, and application code. We work together under the incident response process to restore service safely.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. Where the production ticket comes from
&lt;/h2&gt;

&lt;p&gt;In this scenario, Prometheus detects the elevated error rate and sends the alert to Alertmanager. Alertmanager routes it to PagerDuty. PagerDuty pages the primary on-call engineer. An incident ticket is then created in Jira Service Management through the company's configured integration or incident workflow.&lt;/p&gt;

&lt;p&gt;PagerDuty — Production Alert&lt;/p&gt;

&lt;p&gt;12:15 AM · Payment Platform · Primary On-Call&lt;/p&gt;

&lt;h2&gt;
  
  
  High Payment Failure Rate
&lt;/h2&gt;

&lt;p&gt;Service: &lt;code&gt;payment-api-prod&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Environment: &lt;code&gt;production&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Cluster: &lt;code&gt;northstar-prod-eks&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Namespace: &lt;code&gt;payments-prod&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Trigger: HTTP 5xx rate exceeds the configured threshold for 5 minutes.&lt;/p&gt;

&lt;p&gt;Customer payment authorization is degraded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Jira incident ticket
&lt;/h3&gt;

&lt;p&gt;Jira Service Management · INC-2026-1047&lt;/p&gt;

&lt;p&gt;P1&lt;/p&gt;

&lt;p&gt;Payment authorization failures — customer impact&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Investigating&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Assigned group&lt;/td&gt;
&lt;td&gt;Production SRE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First detected&lt;/td&gt;
&lt;td&gt;12:15 AM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer symptoms&lt;/td&gt;
&lt;td&gt;Payment errors and timeouts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Related change&lt;/td&gt;
&lt;td&gt;CHG-2026-318 — Terraform network update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Impacted service&lt;/td&gt;
&lt;td&gt;Payment API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Description&lt;/p&gt;

&lt;p&gt;Payment success rate has dropped from approximately 99.95% to 41%. Payment API 5xx errors have increased. Kubernetes reports all 12 API Pods as Ready. RDS instance status is Available. Investigate application dependencies, infrastructure changes, and customer impact.&lt;/p&gt;

&lt;p&gt;Initial assignment: Primary on-call SRE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where else might you learn about the incident?
&lt;/h3&gt;

&lt;p&gt;You may see the same incident in the PagerDuty mobile app, Slack incident channel, Jira queue, Grafana dashboard, CloudWatch alarms, or customer support escalation. Different companies use different integrations.&lt;/p&gt;

&lt;p&gt;Student question: “What is the difference between an alert, an incident ticket, and a change ticket?”&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An alert is a monitoring signal that requires attention.&lt;/li&gt;
&lt;li&gt;An incident ticket tracks the unexpected service disruption and response.&lt;/li&gt;
&lt;li&gt;A change ticket documents an intended production change, its approvals, timing, and rollback plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. The incident timeline
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;11:20 PM&lt;/td&gt;
&lt;td&gt;GitHub Actions infrastructure pipeline starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:28 PM&lt;/td&gt;
&lt;td&gt;Terraform plan is reviewed and approved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:40 PM&lt;/td&gt;
&lt;td&gt;Terraform apply completes successfully&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:45 PM&lt;/td&gt;
&lt;td&gt;Infrastructure pipeline reports success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:00 AM&lt;/td&gt;
&lt;td&gt;Payment API error rate begins increasing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:10 AM&lt;/td&gt;
&lt;td&gt;Payment success rate drops sharply&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:15 AM&lt;/td&gt;
&lt;td&gt;PagerDuty pages the primary on-call engineer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:17 AM&lt;/td&gt;
&lt;td&gt;SRE acknowledges and begins triage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:22 AM&lt;/td&gt;
&lt;td&gt;Incident Commander engaged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:30 AM&lt;/td&gt;
&lt;td&gt;Database connectivity errors identified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:40 AM&lt;/td&gt;
&lt;td&gt;Recent infrastructure change becomes the leading suspect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:50 AM&lt;/td&gt;
&lt;td&gt;Recovery change is prepared and reviewed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:05 AM&lt;/td&gt;
&lt;td&gt;Connectivity restored; application recovery monitored&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:20 AM&lt;/td&gt;
&lt;td&gt;Payment success and error metrics return to baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:35 AM&lt;/td&gt;
&lt;td&gt;Incident moves into observation and post-incident follow-up&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These timestamps are the planned case-study narrative, not measured outcomes from the student lab.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The mystery: why healthy Pods cannot process payments
&lt;/h2&gt;

&lt;p&gt;At first, you check Kubernetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output shows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                           READY   STATUS    RESTARTS
payment-api-7d8f5b6c9-a1b2c    1/1     Running   0
payment-api-7d8f5b6c9-d3e4f    1/1     Running   0
payment-api-7d8f5b6c9-g5h6i    1/1     Running   0
...
12 payment-api Pods Ready
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you inspect the Deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment payment-api &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME          READY   UP-TO-DATE   AVAILABLE
payment-api   12/12   12           12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You inspect RDS in AWS and see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB instance: northstar-payments-prod
Status: Available
Engine: PostgreSQL
Port: 5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yet the payment API returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;503&lt;/span&gt; &lt;span class="ne"&gt;Service Unavailable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Application logs contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR payment authorization failed
ERROR could not establish database connection
ERROR connection timeout to postgres endpoint:5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the central lesson of the incident:&lt;/p&gt;

&lt;p&gt;Kubernetes Pod readiness, application dependency health, and successful business transactions are three different things.&lt;/p&gt;

&lt;p&gt;A database can be operational while a particular application cannot connect to it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Class 1 — Detect, assess, and investigate
&lt;/h1&gt;

&lt;p&gt;3 hours · Students act as the primary on-call SRE&lt;/p&gt;

&lt;h2&gt;
  
  
  Class 1 schedule
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Activity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0:00–0:25&lt;/td&gt;
&lt;td&gt;Read incident ticket, identify business impact&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0:25–0:50&lt;/td&gt;
&lt;td&gt;Understand team structure and incident communication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0:50–1:20&lt;/td&gt;
&lt;td&gt;Investigate Kubernetes health&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:20–1:50&lt;/td&gt;
&lt;td&gt;Investigate Grafana and HTTP errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:50–2:20&lt;/td&gt;
&lt;td&gt;Check application logs and database connectivity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2:20–2:45&lt;/td&gt;
&lt;td&gt;Identify next investigation steps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2:45–3:00&lt;/td&gt;
&lt;td&gt;Mock interview and handover&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Task 1 — Your first five minutes
&lt;/h2&gt;

&lt;p&gt;You receive the PagerDuty alert. You are the primary on-call engineer.&lt;/p&gt;

&lt;p&gt;Your interviewer asks:&lt;/p&gt;

&lt;p&gt;“What would you do immediately?”&lt;/p&gt;

&lt;p&gt;A model response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“First, I would acknowledge the PagerDuty alert. Then I would open our monitoring dashboards to validate the impact, including payment success rate, HTTP 5xx errors, latency, and Kubernetes availability. I would determine whether the issue affects all customers or a subset, identify the impacted services, and follow our incident escalation procedure. I would not immediately restart Pods because the evidence does not yet show that restarting them would help.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What you should ask the incident team
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Which payment operations are failing: authorization, capture, refund, or all of them?&lt;/li&gt;
&lt;li&gt;When did the errors begin?&lt;/li&gt;
&lt;li&gt;Are all customers affected or only certain regions or merchants?&lt;/li&gt;
&lt;li&gt;Did an application release, infrastructure change, or database maintenance occur?&lt;/li&gt;
&lt;li&gt;Are failures isolated to one service or shared by multiple services?&lt;/li&gt;
&lt;li&gt;Are transactions being rejected, timing out, or potentially duplicated?&lt;/li&gt;
&lt;li&gt;Is there a known-good recovery procedure?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important: During a payment incident, do not blindly retry failed transactions. A timeout does not necessarily mean a payment was never processed. The application and payment teams must verify transaction status and idempotency before retrying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 2 — Kubernetes investigation
&lt;/h2&gt;

&lt;p&gt;Run the following commands in the designated training namespace. In the production case study, the namespace is &lt;code&gt;payments-prod&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;# Confirm cluster context before running commands&lt;/span&gt;
kubectl config current-context

&lt;span class="c"&gt;# Inspect deployments&lt;/span&gt;
kubectl get deployments &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod

&lt;span class="c"&gt;# Inspect Pods and their nodes&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod &lt;span class="nt"&gt;-o&lt;/span&gt; wide

&lt;span class="c"&gt;# Inspect Services&lt;/span&gt;
kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod

&lt;span class="c"&gt;# Inspect Service endpoints&lt;/span&gt;
kubectl get endpointslices &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod

&lt;span class="c"&gt;# Inspect nodes&lt;/span&gt;
kubectl get nodes &lt;span class="nt"&gt;-o&lt;/span&gt; wide

&lt;span class="c"&gt;# Inspect the payment Deployment&lt;/span&gt;
kubectl describe deployment payment-api &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod

&lt;span class="c"&gt;# Inspect one payment Pod&lt;/span&gt;
kubectl describe pod POD_NAME &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod

&lt;span class="c"&gt;# Review application logs&lt;/span&gt;
kubectl logs POD_NAME &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  What should you conclude?
&lt;/h3&gt;

&lt;p&gt;If all Pods are Ready, you have evidence that Kubernetes considers them eligible to serve traffic. You do not yet have evidence that the payment workflow is functioning correctly.&lt;/p&gt;

&lt;p&gt;Check the readiness probe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod &lt;span class="nt"&gt;-o&lt;/span&gt; yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose you discover:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/ready&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The endpoint checks whether the application process can respond, but it does not test PostgreSQL connectivity.&lt;/p&gt;

&lt;p&gt;Interview follow-up: “Should a readiness probe always connect to the database?”&lt;/p&gt;

&lt;p&gt;No. Dependency-aware readiness checks can be useful, but they require careful design. If every Pod fails readiness during a shared database outage, the Service may lose all endpoints, potentially worsening recovery. Teams often separate lightweight process readiness, dependency health, and end-to-end business transaction monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 3 — Grafana investigation
&lt;/h2&gt;

&lt;p&gt;Your instructor should show four monitoring panels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example incident dashboard
&lt;/h3&gt;

&lt;p&gt;Available API replicas&lt;/p&gt;

&lt;h1&gt;
  
  
  12 / 12
&lt;/h1&gt;

&lt;p&gt;Stable&lt;/p&gt;

&lt;p&gt;Payment success rate&lt;/p&gt;

&lt;h1&gt;
  
  
  41%
&lt;/h1&gt;

&lt;p&gt;Severely degraded&lt;/p&gt;

&lt;p&gt;HTTP 5xx error rate&lt;/p&gt;

&lt;h1&gt;
  
  
  37%
&lt;/h1&gt;

&lt;p&gt;Elevated&lt;/p&gt;

&lt;p&gt;Database connection failures&lt;/p&gt;

&lt;h1&gt;
  
  
  Increasing
&lt;/h1&gt;

&lt;p&gt;Application-side metric&lt;/p&gt;

&lt;h3&gt;
  
  
  PromQL examples
&lt;/h3&gt;

&lt;p&gt;These queries assume that the required Kubernetes and application metrics are actually collected. Metric names such as &lt;code&gt;http_requests_total&lt;/code&gt; and &lt;code&gt;payment_transactions_total&lt;/code&gt; are example application instrumentation; they do not appear automatically from kube-state-metrics.&lt;/p&gt;

&lt;p&gt;Available replicas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;kube_deployment_status_replicas_available&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payments-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payment-api"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Desired replicas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;kube_deployment_spec_replicas&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payments-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payment-api"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTTP 5xx percentage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http_requests_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payment-api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=~&lt;/span&gt;&lt;span class="s2"&gt;"5.."&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="nb"&gt;clamp_min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http_requests_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payment-api"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;])),&lt;/span&gt;
  &lt;span class="mf"&gt;0.001&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Payment success percentage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment_transactions_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="nb"&gt;clamp_min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment_transactions_total&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;])),&lt;/span&gt;
  &lt;span class="mf"&gt;0.001&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;95th percentile HTTP latency&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="nb"&gt;histogram_quantile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;sum&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;le&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http_request_duration_seconds_bucket&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;      &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payment-api"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For HTTP status-code metrics, instrument the application or collect appropriate ingress/load-balancer metrics. Prometheus cannot derive HTTP 503 counts from Pod readiness alone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interviewer asks
&lt;/h3&gt;

&lt;p&gt;“Grafana shows all 12 Pods healthy but the payment success rate is 41%. Where do you investigate next?”&lt;/p&gt;

&lt;p&gt;A strong response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I would investigate the application request path and its dependencies. I would review payment API logs, trace failed requests, check database connection metrics, and test connectivity from the application network. I would also review recent infrastructure and application changes.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Task 4 — Application logs
&lt;/h2&gt;

&lt;p&gt;Example logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00:11:42 INFO  POST /api/payments/authorize
00:11:42 ERROR database connection timeout
00:11:42 ERROR SQLSTATE 08001
00:11:42 WARN  payment authorization unavailable
00:11:42 INFO  response_status=503 duration_ms=5002
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explain to the instructor:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What does &lt;code&gt;SQLSTATE 08001&lt;/code&gt; suggest?&lt;/li&gt;
&lt;li&gt;Does this prove the database server has crashed?&lt;/li&gt;
&lt;li&gt;What is the difference between a connection timeout and an authentication failure?&lt;/li&gt;
&lt;li&gt;Why might the application return 503 while its Pod remains Ready?&lt;/li&gt;
&lt;li&gt;Which team should investigate the database, and which team should investigate the application?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A useful answer to question 2:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“No. A database connection failure can result from networking, security groups, routing, DNS, authentication, database capacity, or a database outage. I would test each layer before deciding which component is responsible.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Class 1 communication exercise
&lt;/h2&gt;

&lt;p&gt;Students should practice this update to the incident commander:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incident update — Payment API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have confirmed significant customer-facing payment failures. Payment success rate has dropped to approximately 41%, and HTTP 5xx errors are elevated.&lt;/p&gt;

&lt;p&gt;All 12 Payment API Pods remain Ready, and the RDS instance reports Available. However, application logs show PostgreSQL connection timeouts.&lt;/p&gt;

&lt;p&gt;We are investigating the application-to-database network path and reviewing recent infrastructure changes with the platform and database teams.&lt;/p&gt;

&lt;p&gt;The root cause is not yet confirmed. Our priority is restoring payment authorization safely and preventing duplicate transactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class 1 homework
&lt;/h3&gt;

&lt;p&gt;Students should submit a short incident update, the commands they would use, their initial hypotheses, and an explanation of why healthy Pods do not guarantee healthy payment processing.&lt;/p&gt;

&lt;h1&gt;
  
  
  Class 2 — Terraform, CI/CD, networking, and database
&lt;/h1&gt;

&lt;p&gt;3 hours · Deep technical investigation&lt;/p&gt;

&lt;h2&gt;
  
  
  Class 2 schedule
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Activity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0:00–0:25&lt;/td&gt;
&lt;td&gt;Review Class 1 evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0:25–0:55&lt;/td&gt;
&lt;td&gt;Trace the payment request to PostgreSQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0:55–1:25&lt;/td&gt;
&lt;td&gt;Investigate database connectivity and metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:25–1:55&lt;/td&gt;
&lt;td&gt;Review GitHub Actions and Terraform change history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:55–2:25&lt;/td&gt;
&lt;td&gt;Compare security group rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2:25–2:45&lt;/td&gt;
&lt;td&gt;Confirm the cause and propose recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2:45–3:00&lt;/td&gt;
&lt;td&gt;Technical interview challenge&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Task 1 — Understand the database connection
&lt;/h2&gt;

&lt;p&gt;The payment application uses PostgreSQL to store payment transactions.&lt;/p&gt;

&lt;p&gt;Example database tables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;payments&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;merchant_id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;amount_cents&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;currency&lt;/span&gt; &lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;idempotency_key&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;payment_events&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;event_id&lt;/span&gt; &lt;span class="n"&gt;BIGSERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payment_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;event_type&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Example payment statuses are &lt;code&gt;PENDING&lt;/code&gt;, &lt;code&gt;AUTHORIZED&lt;/code&gt;, &lt;code&gt;DECLINED&lt;/code&gt;, and &lt;code&gt;FAILED&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In a real payment platform, financial transaction data needs additional controls, auditing, access restrictions, and carefully designed state transitions. This simplified schema is for learning connectivity and SQL troubleshooting, not a complete payment ledger.&lt;/p&gt;

&lt;h3&gt;
  
  
  Normal payment request flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Customer sends &lt;code&gt;POST /api/payments/authorize&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;ALB routes the request to the Payment API in EKS.&lt;/li&gt;
&lt;li&gt;Payment API validates the request and checks its idempotency key.&lt;/li&gt;
&lt;li&gt;Application opens or reuses a PostgreSQL connection.&lt;/li&gt;
&lt;li&gt;Application reads or writes payment state and coordinates the external authorization workflow.&lt;/li&gt;
&lt;li&gt;Application returns the appropriate response and emits metrics.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What happens if step 4 fails?&lt;/p&gt;

&lt;p&gt;The application may be unable to read or persist the payment state. It must not blindly repeat external authorization requests or assume that a timed-out transaction did not succeed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 2 — Test database connectivity
&lt;/h2&gt;

&lt;p&gt;The database engineer confirms that RDS is Available. Your next question is whether the Payment API network can reach the database endpoint on TCP port 5432.&lt;/p&gt;

&lt;p&gt;For the production case study, you would use approved access through the existing application Pod or an authorized diagnostic Pod in the same network context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;# Check the ServiceAccount and Pod configuration&lt;/span&gt;
kubectl get pod POD_NAME &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod &lt;span class="nt"&gt;-o&lt;/span&gt; yaml

&lt;span class="c"&gt;# Inspect relevant application logs&lt;/span&gt;
kubectl logs POD_NAME &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100

&lt;span class="c"&gt;# Check database DNS resolution&lt;/span&gt;
getent hosts DB_ENDPOINT

&lt;span class="c"&gt;# Check TCP connectivity&lt;/span&gt;
nc &lt;span class="nt"&gt;-vz&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; 5 DB_ENDPOINT 5432

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

&lt;/div&gt;



&lt;p&gt;The last two commands must run in an authorized environment with equivalent network access to the affected application, not simply on an unrelated EC2 management host. A successful connection from a bastion does not prove that an EKS Pod can connect.&lt;/p&gt;

&lt;p&gt;Expected investigation evidence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS resolution: successful

TCP connection:
connect to DB_ENDPOINT port 5432:
Connection timed out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This suggests a network-path problem but does not yet identify the exact AWS rule responsible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interviewer follow-ups
&lt;/h3&gt;

&lt;p&gt;“What if DNS fails?”&lt;/p&gt;

&lt;p&gt;Investigate CoreDNS, VPC DNS configuration, DNS records, resolver access, and the endpoint being used.&lt;/p&gt;

&lt;p&gt;“What if DNS works but TCP times out?”&lt;/p&gt;

&lt;p&gt;Investigate security groups, Network ACLs, routing, NetworkPolicies, database endpoint reachability, and possible network packet drops.&lt;/p&gt;

&lt;p&gt;“What if TCP succeeds but PostgreSQL authentication fails?”&lt;/p&gt;

&lt;p&gt;Investigate database credentials, IAM database authentication if configured, Secrets Manager, PostgreSQL roles, SSL requirements, and authentication settings.&lt;/p&gt;

&lt;p&gt;“What if TCP succeeds but SQL queries are slow?”&lt;/p&gt;

&lt;p&gt;Investigate query plans, locks, active sessions, connection pools, CPU, I/O, and database wait events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 3 — Inspect PostgreSQL health
&lt;/h2&gt;

&lt;p&gt;The database team runs approved diagnostic queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="c1"&gt;-- Verify database responds&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Count current connections&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;active_connections&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Inspect connection states&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Check configured connection limit&lt;/span&gt;
&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;max_connections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Review sessions waiting on resources&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;wait_event_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;wait_event&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;wait_event&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If the database is responsive and the connection count is low, but Payment API Pods cannot connect, the team should investigate the network path.&lt;/p&gt;

&lt;p&gt;A low connection count alone does not prove a security group problem. It becomes useful evidence when combined with timeouts, recent changes, and network configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS RDS checks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws rds describe-db-instances &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--db-instance-identifier&lt;/span&gt; northstar-payments-prod &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'DBInstances[0].{Status:DBInstanceStatus,Endpoint:Endpoint.Address,Port:Endpoint.Port,VpcSecurityGroups:VpcSecurityGroups}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check CloudWatch or RDS monitoring for database connections, CPU utilization, free memory, storage, and relevant logs. Enhanced Monitoring and Performance Insights/Database Insights may provide deeper diagnostics if configured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 4 — Investigate the CI/CD pipeline
&lt;/h2&gt;

&lt;p&gt;The release engineer discovers a GitHub Actions workflow:&lt;/p&gt;

&lt;p&gt;GitHub Actions — Production Infrastructure&lt;/p&gt;

&lt;p&gt;Succeeded&lt;/p&gt;

&lt;p&gt;Workflow: terraform-production.yml · Completed 11:45 PM&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Checkout repository&lt;/li&gt;
&lt;li&gt; Terraform format and validate&lt;/li&gt;
&lt;li&gt; Terraform plan&lt;/li&gt;
&lt;li&gt; Production approval&lt;/li&gt;
&lt;li&gt; Terraform apply&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interviewer: “If the Terraform pipeline succeeded, how could it have caused the incident?”&lt;/p&gt;

&lt;p&gt;Answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“A successful Terraform apply means the requested infrastructure changes were applied. It does not prove that application connectivity or business functionality remained healthy. The pipeline may lack post-deployment integration tests or application-level validation.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Production workflow example
&lt;/h3&gt;

&lt;p&gt;Students should understand this pipeline structure:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

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

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="c1"&gt;# Configure approved AWS OIDC credentials&lt;/span&gt;
      &lt;span class="c1"&gt;# Install a pinned, approved Terraform version&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform fmt -check&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init -input=false&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform validate&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan -out=tfplan&lt;/span&gt;

  &lt;span class="c1"&gt;# Production apply should be a separate approved job.&lt;/span&gt;
  &lt;span class="c1"&gt;# Use a protected environment, artifact integrity&lt;/span&gt;
  &lt;span class="c1"&gt;# checks, and the reviewed saved plan.&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This is a teaching skeleton, not a complete production-ready workflow. In a real pipeline, the saved plan must be securely transferred between jobs, access controlled, and applied only after approval.&lt;/p&gt;

&lt;h3&gt;
  
  
  Questions students must answer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;What is the difference between &lt;code&gt;terraform plan&lt;/code&gt; and &lt;code&gt;terraform apply&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;What does Terraform state store?&lt;/li&gt;
&lt;li&gt;Why use a remote backend and state locking?&lt;/li&gt;
&lt;li&gt;Why should GitHub Actions authenticate to AWS using OIDC rather than long-lived access keys?&lt;/li&gt;
&lt;li&gt;What does a protected GitHub environment accomplish?&lt;/li&gt;
&lt;li&gt;Why is manual approval useful but not sufficient?&lt;/li&gt;
&lt;li&gt;What post-apply checks would have detected the payment outage?&lt;/li&gt;
&lt;li&gt;Why can an infrastructure change fail without any new application image?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Task 5 — The Terraform change
&lt;/h2&gt;

&lt;p&gt;The platform engineer compares the previous and current security group configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before the change
&lt;/h3&gt;

&lt;p&gt;The RDS security group allows PostgreSQL access from the EKS application security group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc_security_group_ingress_rule"&lt;/span&gt; &lt;span class="s2"&gt;"postgres_from_eks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;security_group_id&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;referenced_security_group_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;ip_protocol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After the change
&lt;/h3&gt;

&lt;p&gt;A Terraform refactor accidentally replaces the application security group reference with an unrelated security group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc_security_group_ingress_rule"&lt;/span&gt; &lt;span class="s2"&gt;"postgres_from_eks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;security_group_id&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;referenced_security_group_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;management&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;ip_protocol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important: The code is illustrative. Actual EKS Pod network traffic may use node security groups or Pod security groups depending on the VPC CNI and security-groups-for-Pods configuration. The effective source security group must be verified in the actual architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happened?
&lt;/h3&gt;

&lt;p&gt;The authorized source for PostgreSQL traffic was changed.&lt;/p&gt;

&lt;p&gt;The database remained healthy, and the EKS Pods remained Ready, but new database connections from the application network were no longer permitted by the intended ingress rule.&lt;/p&gt;

&lt;p&gt;Existing established connections may continue temporarily because AWS security groups are stateful and connection tracking can preserve some flows. As connections close, recycle, or time out, application failures may increase.&lt;/p&gt;

&lt;p&gt;This explains why the outage can appear after the Terraform apply rather than exactly when the change is made.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compare the infrastructure change
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;-10&lt;/span&gt;

git diff PREVIOUS_COMMIT CURRENT_COMMIT &lt;span class="nt"&gt;--&lt;/span&gt; terraform/

terraform plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For AWS-side verification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ec2 describe-security-groups &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--group-ids&lt;/span&gt; sg-EXAMPLE &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'SecurityGroups[*].IpPermissions'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not assume a security group ID from a screenshot or example. Identify the actual RDS security group and the effective source security group first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Root cause evidence chain
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Terraform changed the RDS ingress source security group.&lt;/li&gt;
&lt;li&gt;The infrastructure change occurred before the payment errors.&lt;/li&gt;
&lt;li&gt;Payment API logs show database connection timeouts.&lt;/li&gt;
&lt;li&gt;RDS remains operational and responsive from an authorized network.&lt;/li&gt;
&lt;li&gt;The application network cannot establish new TCP connections to port 5432.&lt;/li&gt;
&lt;li&gt;Restoring the approved application security group rule restores connectivity and payment processing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This combination of change history, network testing, application logs, and successful recovery provides much stronger causal evidence than timing alone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class 2 interview challenge
&lt;/h3&gt;

&lt;p&gt;“How would you prove the Terraform change caused the payment failures rather than a PostgreSQL outage?”&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;“I would compare the Terraform plan and AWS security group configuration with the last known-good state, verify that the database itself is responsive, and test connectivity from the affected application network. I would correlate the network failures with the infrastructure change and confirm that restoring the correct rule resolves the connectivity issue.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Class 3 — Recovery, prevention, and interview mastery
&lt;/h1&gt;

&lt;p&gt;3 hours · Students act as incident responders and interview candidates&lt;/p&gt;

&lt;h2&gt;
  
  
  Class 3 schedule
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Activity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0:00–0:30&lt;/td&gt;
&lt;td&gt;Decide on mitigation and evaluate rollback risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0:30–1:00&lt;/td&gt;
&lt;td&gt;Restore database connectivity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:00–1:30&lt;/td&gt;
&lt;td&gt;Verify Kubernetes, database, and customer transactions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:30–2:00&lt;/td&gt;
&lt;td&gt;Write the incident report and preventive actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2:00–2:40&lt;/td&gt;
&lt;td&gt;Advanced technical interview&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2:40–3:00&lt;/td&gt;
&lt;td&gt;Final individual interview assessment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Task 1 — How do you restore production?
&lt;/h2&gt;

&lt;p&gt;The platform engineer has identified the incorrect RDS security group ingress rule.&lt;/p&gt;

&lt;p&gt;The incident commander asks:&lt;/p&gt;

&lt;p&gt;“What is the safest and fastest way to restore service?”&lt;/p&gt;

&lt;p&gt;The team should evaluate two possible recovery approaches.&lt;/p&gt;

&lt;p&gt;Option A — Revert the incorrect Terraform change. Restore the previously approved application security group rule in code, review the plan, obtain the necessary approval, and apply the corrective configuration.&lt;/p&gt;

&lt;p&gt;Option B — Emergency network change. If the approved emergency procedure allows an immediate AWS-side correction, an authorized engineer can restore the exact known-good rule and subsequently reconcile Terraform code and state. This must be documented and reviewed to avoid configuration drift.&lt;/p&gt;

&lt;p&gt;Do not open PostgreSQL to &lt;code&gt;0.0.0.0/0&lt;/code&gt;, disable all security groups, or expose RDS publicly as a troubleshooting shortcut.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example corrected Terraform configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc_security_group_ingress_rule"&lt;/span&gt; &lt;span class="s2"&gt;"postgres_from_eks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;security_group_id&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;referenced_security_group_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;ip_protocol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;

  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PostgreSQL access from approved EKS application SG"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Interviewer asks
&lt;/h3&gt;

&lt;p&gt;“Would you simply run &lt;code&gt;terraform apply&lt;/code&gt; again?”&lt;/p&gt;

&lt;p&gt;No. First inspect the planned changes. Applying the same incorrect configuration again would not solve the incident.&lt;/p&gt;

&lt;p&gt;“Would you run &lt;code&gt;terraform destroy&lt;/code&gt;?”&lt;/p&gt;

&lt;p&gt;No. Destroying production infrastructure would be highly dangerous and unrelated to this targeted connectivity issue.&lt;/p&gt;

&lt;p&gt;“Would you roll back the Kubernetes Deployment?”&lt;/p&gt;

&lt;p&gt;Not automatically. If the root cause is an RDS security group rule, reverting the application image may have no effect. The corrective action should target the confirmed cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 2 — Verify recovery at every layer
&lt;/h2&gt;

&lt;p&gt;After the approved rule is restored, verify the application network can connect to PostgreSQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;# Verify application Pod health&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod

&lt;span class="c"&gt;# Verify Deployment availability&lt;/span&gt;
kubectl get deployment payment-api &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod

&lt;span class="c"&gt;# Verify Service endpoints&lt;/span&gt;
kubectl get endpointslices &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod

&lt;span class="c"&gt;# Check recent application errors&lt;/span&gt;
kubectl logs deployment/payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100

&lt;span class="c"&gt;# Confirm application rollout state&lt;/span&gt;
kubectl rollout status &lt;span class="se"&gt;\&lt;/span&gt;
  deployment/payment-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-prod

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

&lt;/div&gt;



&lt;p&gt;Then verify database connectivity using an approved diagnostic path, confirm the application can perform its expected queries, and run a controlled synthetic payment test using a dedicated nonfinancial test transaction or payment-provider sandbox.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recovery criteria
&lt;/h3&gt;

&lt;p&gt;Students must demonstrate all five checks&lt;/p&gt;

&lt;p&gt;Payment API can establish PostgreSQL connections&lt;/p&gt;

&lt;p&gt;Database queries succeed without exposing sensitive records&lt;/p&gt;

&lt;p&gt;Customer-facing 5xx rate returns to normal&lt;/p&gt;

&lt;p&gt;Payment success rate returns to expected baseline&lt;/p&gt;

&lt;p&gt;No unintended duplicate payments or unresolved transaction states&lt;/p&gt;

&lt;p&gt;0 of 5 recovery checks completed&lt;/p&gt;

&lt;p&gt;Remember: A green Grafana dashboard alone does not establish that customer transactions are correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 3 — Write the post-incident report
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Postmortem — INC-2026-1047
&lt;/h2&gt;

&lt;p&gt;Incident summary&lt;/p&gt;

&lt;p&gt;Payment authorization was degraded following a production Terraform networking change.&lt;/p&gt;

&lt;p&gt;Customer impact&lt;/p&gt;

&lt;p&gt;The illustrative payment success rate declined from 99.95% to 41%, with elevated HTTP 5xx errors and latency.&lt;/p&gt;

&lt;p&gt;Technical root cause&lt;/p&gt;

&lt;p&gt;An infrastructure refactor changed the source security group allowed to reach RDS PostgreSQL on TCP port 5432. Application Pods remained Ready because their readiness checks did not verify database-dependent business functionality.&lt;/p&gt;

&lt;p&gt;Contributing factors&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform validation confirmed configuration syntax but did not test application-to-database connectivity.&lt;/li&gt;
&lt;li&gt;The CI/CD pipeline lacked a post-apply payment workflow smoke test.&lt;/li&gt;
&lt;li&gt;The alerting design detected payment failures but did not immediately identify the affected network dependency.&lt;/li&gt;
&lt;li&gt;The readiness probe was insufficient as an indicator of end-to-end payment health.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mitigation&lt;/p&gt;

&lt;p&gt;The team restored the approved database ingress rule and verified application connectivity, transaction processing, and recovery metrics.&lt;/p&gt;

&lt;p&gt;Preventive actions&lt;/p&gt;

&lt;p&gt;Introduce security group policy checks, infrastructure change review, post-deployment connectivity testing, synthetic payment monitoring, and clearer incident runbooks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who owns the preventive actions?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Owner&lt;/th&gt;
&lt;th&gt;Verification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Restore and review security group configuration&lt;/td&gt;
&lt;td&gt;Platform engineer&lt;/td&gt;
&lt;td&gt;Terraform plan and AWS configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add network policy tests to CI/CD&lt;/td&gt;
&lt;td&gt;Platform / security&lt;/td&gt;
&lt;td&gt;Automated policy checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add post-apply connectivity smoke test&lt;/td&gt;
&lt;td&gt;DevOps / SRE&lt;/td&gt;
&lt;td&gt;Successful synthetic check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Improve payment error metrics&lt;/td&gt;
&lt;td&gt;Backend team&lt;/td&gt;
&lt;td&gt;Grafana dashboard and alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Improve transaction reconciliation&lt;/td&gt;
&lt;td&gt;Backend / database&lt;/td&gt;
&lt;td&gt;Controlled recovery tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update incident runbook&lt;/td&gt;
&lt;td&gt;SRE&lt;/td&gt;
&lt;td&gt;Reviewed incident exercise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review production change approvals&lt;/td&gt;
&lt;td&gt;Release engineering&lt;/td&gt;
&lt;td&gt;Change audit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Practical hands-on lab — Build the failure safely
&lt;/h1&gt;

&lt;p&gt;Students, you will reproduce the application-to-database connectivity failure in your own training EKS cluster.&lt;/p&gt;

&lt;p&gt;You will not modify an actual bank, customer database, or production security group.&lt;/p&gt;

&lt;p&gt;The safest classroom version uses a PostgreSQL Pod inside a dedicated namespace and a Kubernetes NetworkPolicy to block connectivity. This reproduces the symptom and troubleshooting workflow without changing live AWS infrastructure.&lt;/p&gt;

&lt;p&gt;For the Terraform portion, you will separately review an example security group change and its plan. An optional isolated AWS RDS exercise can be added later when your instructor has prepared a dedicated account, budget, and recovery procedure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lab architecture
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Step 1 — Create an isolated namespace
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — Deploy PostgreSQL
&lt;/h2&gt;

&lt;p&gt;This database is temporary and contains no real customer data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres-secret&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lab-only-change-me"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;labuser&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres-secret&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sh&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;-c&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pg_isready -U labuser -d payments&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;50m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;128Mi&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;512Mi&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Save this as &lt;code&gt;postgres-lab.yaml&lt;/code&gt; and apply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; postgres-lab.yaml

kubectl rollout status deployment/lab-postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lab uses ephemeral PostgreSQL storage. Data is lost when the database Pod is replaced. That is acceptable for a disposable connectivity exercise but not for a production database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Verify normal connectivity
&lt;/h2&gt;

&lt;p&gt;Use a temporary PostgreSQL client Pod.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run payment-db-client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres:16 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"PGPASSWORD=lab-only-change-me"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--command&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;3600
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait until it is Running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Ready &lt;span class="se"&gt;\&lt;/span&gt;
  pod/payment-db-client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;120s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run a database query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  payment-db-client &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  psql &lt;span class="nt"&gt;-h&lt;/span&gt; lab-postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-U&lt;/span&gt; labuser &lt;span class="nt"&gt;-d&lt;/span&gt; payments &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT 1;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ?column?
----------
        1
(1 row)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This proves that the client can reach PostgreSQL before the incident is introduced.&lt;/p&gt;

&lt;p&gt;The example password is deliberately disposable. Never use real database credentials in shared class terminals or recorded commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Inject the incident
&lt;/h2&gt;

&lt;p&gt;Apply a NetworkPolicy that selects the PostgreSQL Pod and allows no incoming connections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;block-postgres-ingress&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-incident-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lab-postgres&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Save as &lt;code&gt;block-postgres.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; block-postgres.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prerequisite: The cluster must have a network policy implementation that enforces Kubernetes NetworkPolicy, such as a properly configured Amazon VPC CNI network policy agent or another compatible CNI. Otherwise, the policy may exist without actually blocking traffic.&lt;/p&gt;

&lt;p&gt;Test again with a timeout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  payment-db-client &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'PGCONNECT_TIMEOUT=5 psql -h lab-postgres -U labuser -d payments -c "SELECT 1;"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected on a correctly enforcing cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;connection to server at "lab-postgres" failed:
Connection timed out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Students should now investigate why PostgreSQL is Running and Ready but the client cannot connect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl get networkpolicy &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab

kubectl describe networkpolicy block-postgres-ingress &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Student challenge
&lt;/h3&gt;

&lt;p&gt;You are not told that the instructor introduced a NetworkPolicy.&lt;/p&gt;

&lt;p&gt;Your job is to identify the exact resource that changed and explain how it prevents database access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 — Restore service
&lt;/h2&gt;

&lt;p&gt;Once you have identified and documented the cause, remove the injected policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete networkpolicy block-postgres-ingress &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  payment-db-client &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  psql &lt;span class="nt"&gt;-h&lt;/span&gt; lab-postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-U&lt;/span&gt; labuser &lt;span class="nt"&gt;-d&lt;/span&gt; payments &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT 1;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected: &lt;code&gt;SELECT 1&lt;/code&gt; succeeds.&lt;/p&gt;

&lt;p&gt;Clean up the client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod payment-db-client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; payments-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the entire lab is complete, the instructor can delete the dedicated namespace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Important difference between the lab and production
&lt;/h3&gt;

&lt;p&gt;The production case study involves an AWS security group changed by Terraform. The hands-on exercise uses Kubernetes NetworkPolicy to reproduce blocked database traffic safely.&lt;/p&gt;

&lt;p&gt;Both teach network connectivity troubleshooting, but they are different control planes. Students must be able to explain that distinction during an interview.&lt;/p&gt;

&lt;p&gt;Also, this initial lab tests connectivity directly; it does not yet deploy a complete payment API, transaction simulator, or the custom payment metrics used in the fictional dashboard. Those would be additional components if the class needs a fully instrumented end-to-end payment workflow.&lt;/p&gt;

&lt;h1&gt;
  
  
  Advanced interview question bank
&lt;/h1&gt;

&lt;p&gt;Practice the following questions without looking at the answers first.&lt;/p&gt;

&lt;p&gt;Incident response&lt;/p&gt;

&lt;p&gt;1 / 17&lt;/p&gt;

&lt;h2&gt;
  
  
  You receive a payment failure alert. What are your first five actions?
&lt;/h2&gt;

&lt;p&gt;Show model answerFollow-up&lt;/p&gt;

&lt;p&gt; PreviousNext &lt;/p&gt;

&lt;h1&gt;
  
  
  Final mock interview: Tell me about a critical production incident
&lt;/h1&gt;

&lt;p&gt;Students, your final task is to explain the entire incident in approximately three minutes. This is a model answer for discussing the case study. Adapt it to your actual experience rather than claiming to have personally resolved an incident you only practiced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Incident — Payment API Database Connectivity Failure
&lt;/h2&gt;

&lt;p&gt;One complex production incident scenario I worked through involved a customer-facing payment processing application running on AWS EKS with PostgreSQL on Amazon RDS.&lt;/p&gt;

&lt;p&gt;The environment used Terraform for infrastructure management, GitHub Actions for CI/CD, and Prometheus, Grafana, CloudWatch, and PagerDuty for monitoring and alerting.&lt;/p&gt;

&lt;p&gt;The incident began when the payment success rate dropped significantly, from approximately 99.95% to 41%. Customers were experiencing payment failures and HTTP 5xx errors.&lt;/p&gt;

&lt;p&gt;My first step would be to acknowledge the PagerDuty alert and investigate the customer impact through Grafana. I would check the error rate, latency, request volume, and Kubernetes availability.&lt;/p&gt;

&lt;p&gt;Interestingly, all 12 Payment API Pods were Running and Ready, and the RDS database itself reported Available.&lt;/p&gt;

&lt;p&gt;This indicated that the problem might be outside basic Kubernetes Pod health.&lt;/p&gt;

&lt;p&gt;I would inspect the application logs, where I would find PostgreSQL connection timeouts. I would then work with the database and cloud platform teams to investigate database health and the network path from EKS to RDS.&lt;/p&gt;

&lt;p&gt;I would check DNS resolution, TCP connectivity on port 5432, security group rules, and any relevant Kubernetes NetworkPolicies.&lt;/p&gt;

&lt;p&gt;At the same time, I would review recent production changes. The release engineering team would identify a successful Terraform infrastructure deployment shortly before the errors started.&lt;/p&gt;

&lt;p&gt;By comparing the Terraform change with the previous known-good configuration, we would identify that the RDS security group ingress rule had been changed to reference the wrong source security group.&lt;/p&gt;

&lt;p&gt;The database itself was operational, but the application could no longer reliably establish new database connections.&lt;/p&gt;

&lt;p&gt;I would coordinate with the incident commander and platform team to restore the previously approved security group rule using the authorized emergency change procedure.&lt;/p&gt;

&lt;p&gt;After the correction, I would verify connectivity from the application network, confirm successful database operations, and monitor payment success rate, HTTP errors, latency, and transaction reconciliation.&lt;/p&gt;

&lt;p&gt;I would not declare recovery based only on Kubernetes Pod status. I would verify that the customer-facing payment workflow was functioning correctly.&lt;/p&gt;

&lt;p&gt;Following recovery, I would participate in the postmortem and recommend stronger Terraform policy checks, post-deployment connectivity testing, synthetic payment monitoring, and improved incident runbooks.&lt;/p&gt;

&lt;p&gt;The main lesson from this incident is that healthy Kubernetes Pods and a healthy database do not necessarily mean the complete application is healthy. As a DevOps engineer, I need to investigate the full request path and work across infrastructure, application, database, and security teams to restore service safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final evaluation rubric
&lt;/h2&gt;

&lt;p&gt;Use this scorecard to assess each student during Class 3.&lt;/p&gt;

&lt;p&gt;Mock interview score&lt;/p&gt;

&lt;p&gt;Adjust scores as the student answers&lt;/p&gt;

&lt;h1&gt;
  
  
  0 / 100
&lt;/h1&gt;

&lt;p&gt;Needs more practice&lt;/p&gt;

&lt;p&gt;Incident impact and first response&lt;/p&gt;

&lt;p&gt;0 / 15&lt;/p&gt;

&lt;p&gt;Kubernetes investigation&lt;/p&gt;

&lt;p&gt;0 / 15&lt;/p&gt;

&lt;p&gt;Database and networking diagnosis&lt;/p&gt;

&lt;p&gt;0 / 20&lt;/p&gt;

&lt;p&gt;Terraform and CI/CD investigation&lt;/p&gt;

&lt;p&gt;0 / 20&lt;/p&gt;

&lt;p&gt;Mitigation and recovery verification&lt;/p&gt;

&lt;p&gt;0 / 15&lt;/p&gt;

&lt;p&gt;Communication and postmortem&lt;/p&gt;

&lt;p&gt;0 / 15&lt;/p&gt;

&lt;p&gt;Reset for next student&lt;/p&gt;

&lt;h2&gt;
  
  
  What interviewers are really evaluating
&lt;/h2&gt;

&lt;p&gt;This incident is especially useful for DevOps Engineer, Site Reliability Engineer, Platform Engineer, Cloud Infrastructure Engineer, and DevSecOps interviews because it tests several competencies together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes: Understanding that Pod readiness is not the same as business functionality.&lt;/li&gt;
&lt;li&gt;AWS: Knowing how VPC networking, security groups, EKS, and RDS interact.&lt;/li&gt;
&lt;li&gt;Terraform: Understanding change management, infrastructure drift, and safe recovery.&lt;/li&gt;
&lt;li&gt;CI/CD: Recognizing that a successful pipeline does not guarantee a successful production outcome.&lt;/li&gt;
&lt;li&gt;Database: Knowing how to distinguish connectivity, authentication, performance, and availability failures.&lt;/li&gt;
&lt;li&gt;Monitoring: Using technical and business metrics together.&lt;/li&gt;
&lt;li&gt;Incident management: Communicating, escalating, mitigating, verifying, and documenting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Students should be able to explain not just which command they would run, but what question that command answers.&lt;/p&gt;

&lt;p&gt;Your final assignment: Explain why the Payment API could have 12 healthy Kubernetes Pods, an Available PostgreSQL RDS instance, and a successful Terraform deployment while customer payments were failing—and describe the evidence needed to identify and fix the real cause.&lt;/p&gt;

&lt;p&gt;That is the central engineering challenge for these three classes.&lt;/p&gt;

</description>
      <category>sre</category>
      <category>kubernetes</category>
      <category>aws</category>
      <category>devops</category>
    </item>
    <item>
      <title>JumpToTech DevOps Bootcamp Kubernetes Production Support Lab — From Deployment to HTTP Request Troubleshooting</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Thu, 29 Oct 2026 15:48:47 +0000</pubDate>
      <link>https://dev.to/jumptotech/jumptotech-devops-bootcamp-kubernetes-production-support-lab-from-deployment-to-http-request-4ech</link>
      <guid>https://dev.to/jumptotech/jumptotech-devops-bootcamp-kubernetes-production-support-lab-from-deployment-to-http-request-4ech</guid>
      <description>&lt;p&gt;&lt;strong&gt;Level:&lt;/strong&gt; Beginner to Intermediate\&lt;br&gt;
&lt;strong&gt;Role:&lt;/strong&gt; DevOps Engineer / Cloud Engineer / Site Reliability Engineer\&lt;br&gt;
&lt;strong&gt;Project:&lt;/strong&gt; Restaurant Company\&lt;br&gt;
&lt;strong&gt;Environment:&lt;/strong&gt; Kubernetes (Amazon EKS, kind, or minikube)\&lt;br&gt;
&lt;strong&gt;Estimated time:&lt;/strong&gt; 3–4 hours\&lt;br&gt;
&lt;strong&gt;Assignment type:&lt;/strong&gt; Hands-on Lab + Simulated Production Incident + Interview Preparation&lt;/p&gt;


&lt;h1&gt;
  
  
  PART 1 — YOUR ROLE AS A DEVOPS ENGINEER
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Welcome to Restaurant Company
&lt;/h2&gt;

&lt;p&gt;Imagine you have recently joined Restaurant Company as a DevOps Engineer.&lt;/p&gt;

&lt;p&gt;Restaurant Company has a web application that customers use to view restaurant information and place orders.&lt;/p&gt;

&lt;p&gt;The application runs in Kubernetes.&lt;/p&gt;

&lt;p&gt;Your responsibility is to help ensure that the application is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Available to customers.&lt;/li&gt;
&lt;li&gt;Running on healthy Kubernetes Pods.&lt;/li&gt;
&lt;li&gt;Accessible through the correct network routes.&lt;/li&gt;
&lt;li&gt;Deployed reliably through CI/CD pipelines.&lt;/li&gt;
&lt;li&gt;Monitored for failures.&lt;/li&gt;
&lt;li&gt;Recoverable when incidents occur.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are also responsible for communicating with developers, other DevOps engineers, SREs, engineering managers, and incident responders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your job is not simply to execute commands. Your job is to investigate problems, understand the impact, restore service safely, and communicate clearly.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  1.1 Tools used by your company
&lt;/h2&gt;

&lt;p&gt;For this simulated environment, assume your company uses:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;td&gt;Application source code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;td&gt;CI/CD automation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;td&gt;Container image packaging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon ECR&lt;/td&gt;
&lt;td&gt;Container image registry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon EKS&lt;/td&gt;
&lt;td&gt;Managed Kubernetes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kubectl&lt;/td&gt;
&lt;td&gt;Kubernetes administration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jira / ServiceNow&lt;/td&gt;
&lt;td&gt;Incident tickets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slack / Microsoft Teams&lt;/td&gt;
&lt;td&gt;Team communication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prometheus&lt;/td&gt;
&lt;td&gt;Application and infrastructure metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grafana&lt;/td&gt;
&lt;td&gt;Monitoring dashboards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon CloudWatch&lt;/td&gt;
&lt;td&gt;AWS monitoring and logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CoreDNS&lt;/td&gt;
&lt;td&gt;Internal Kubernetes DNS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS ALB&lt;/td&gt;
&lt;td&gt;External HTTP/HTTPS routing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Different companies may use different tools. The concepts remain similar.&lt;/p&gt;


&lt;h1&gt;
  
  
  PART 2 — UNDERSTAND THE APPLICATION ARCHITECTURE
&lt;/h1&gt;

&lt;p&gt;Before troubleshooting production issues, you must understand how the application reaches Kubernetes.&lt;/p&gt;
&lt;h2&gt;
  
  
  2.1 How an application is deployed
&lt;/h2&gt;

&lt;p&gt;A developer writes application code and pushes it to GitHub.&lt;/p&gt;

&lt;p&gt;A typical CI/CD workflow then performs the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developer pushes code to a GitHub repository.&lt;/li&gt;
&lt;li&gt;GitHub Actions starts a CI/CD pipeline.&lt;/li&gt;
&lt;li&gt;The pipeline checks out the source code.&lt;/li&gt;
&lt;li&gt;The pipeline installs dependencies and runs tests.&lt;/li&gt;
&lt;li&gt;Docker builds a container image.&lt;/li&gt;
&lt;li&gt;The image is pushed to Amazon ECR.&lt;/li&gt;
&lt;li&gt;The deployment workflow updates the Kubernetes Deployment to use the new image.&lt;/li&gt;
&lt;li&gt;The Kubernetes API Server accepts the updated desired state.&lt;/li&gt;
&lt;li&gt;The Deployment Controller manages the ReplicaSet.&lt;/li&gt;
&lt;li&gt;The ReplicaSet Controller maintains the required number of Pods.&lt;/li&gt;
&lt;li&gt;The Scheduler selects suitable Worker Nodes for new Pods.&lt;/li&gt;
&lt;li&gt;kubelet on each assigned Worker Node works with the container runtime to start the containers.&lt;/li&gt;
&lt;li&gt;The CNI implementation configures Pod networking.&lt;/li&gt;
&lt;li&gt;Readiness probes determine whether the application Pods are ready to receive traffic.&lt;/li&gt;
&lt;li&gt;Kubernetes Service endpoints are updated to reflect eligible backends.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; This is the typical production deployment architecture. In this lab, we will create Kubernetes resources manually using YAML and kubectl. We are not building a complete GitHub Actions/ECR pipeline today.&lt;/p&gt;
&lt;h2&gt;
  
  
  2.2 Kubernetes component responsibilities
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;API Server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API Server is the entry point for Kubernetes API requests. When you execute &lt;code&gt;kubectl apply&lt;/code&gt;, kubectl sends the requested configuration to the API Server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;etcd&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;etcd stores Kubernetes cluster state, including the desired state of Kubernetes resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment Controller&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Deployment Controller manages ReplicaSets and application rollouts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ReplicaSet Controller&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ReplicaSet Controller ensures that the desired number of Pods exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scheduler&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Scheduler selects an appropriate Worker Node for a Pod that has not yet been assigned to a Node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;kubelet&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;kubelet is the agent running on a Kubernetes Node. It works with the container runtime to maintain assigned Pods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Container Runtime&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The container runtime, such as containerd, manages container image pulling and container execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linux Kernel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Linux Kernel provides the underlying operating system functionality, including processes, networking, namespaces, cgroups, and resource management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CNI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Container Network Interface implementation configures Pod networking. Depending on the CNI plugin, this includes interfaces, IP allocation, and routes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CoreDNS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CoreDNS resolves Kubernetes Service DNS names into their corresponding Service IP addresses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EndpointSlices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;EndpointSlices publish backend endpoint information associated with Kubernetes Services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;kube-proxy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In clusters using kube-proxy, it watches Services and EndpointSlices and configures the Service networking dataplane. In iptables mode, Linux Netfilter processes packets according to the programmed rules.&lt;/p&gt;

&lt;p&gt;Other Kubernetes clusters may use different networking implementations, such as eBPF-based Service routing.&lt;/p&gt;


&lt;h1&gt;
  
  
  PART 3 — YOUR FIRST PRODUCTION TICKET
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Incident Ticket: INC-2026-1042
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Title:&lt;/strong&gt; Restaurant Backend Service Unavailable\&lt;br&gt;
&lt;strong&gt;Priority:&lt;/strong&gt; P2 — High (simulated)\&lt;br&gt;
&lt;strong&gt;Environment:&lt;/strong&gt; Kubernetes\&lt;br&gt;
&lt;strong&gt;Assigned Team:&lt;/strong&gt; DevOps / Platform Engineering\&lt;br&gt;
&lt;strong&gt;Status:&lt;/strong&gt; Open — Investigating&lt;/p&gt;
&lt;h3&gt;
  
  
  Incident description
&lt;/h3&gt;

&lt;p&gt;Customers are reporting that the Restaurant application cannot retrieve backend information.&lt;/p&gt;

&lt;p&gt;Monitoring indicates that application requests are failing.&lt;/p&gt;

&lt;p&gt;The Kubernetes Deployment appears healthy, but requests to the backend Service are unsuccessful.&lt;/p&gt;
&lt;h3&gt;
  
  
  Business impact
&lt;/h3&gt;

&lt;p&gt;Customers may be unable to view restaurant information or complete certain application workflows.&lt;/p&gt;

&lt;p&gt;Your task is to investigate the issue, identify the root cause, restore connectivity, and document the resolution.&lt;/p&gt;
&lt;h2&gt;
  
  
  3.1 Where will you receive the ticket?
&lt;/h2&gt;

&lt;p&gt;In a real company, incidents may be reported through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jira or ServiceNow.&lt;/li&gt;
&lt;li&gt;PagerDuty or another on-call alerting system.&lt;/li&gt;
&lt;li&gt;Grafana or Prometheus alerts.&lt;/li&gt;
&lt;li&gt;CloudWatch alarms.&lt;/li&gt;
&lt;li&gt;Slack or Microsoft Teams.&lt;/li&gt;
&lt;li&gt;Customer support escalation.&lt;/li&gt;
&lt;li&gt;Developer reports.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;A monitoring system detects failed HTTP requests and creates an alert.&lt;/p&gt;

&lt;p&gt;The alert reaches the on-call engineer.&lt;/p&gt;

&lt;p&gt;The engineer acknowledges the alert, reviews the impact, and opens or updates the incident ticket.&lt;/p&gt;

&lt;p&gt;The incident is then investigated according to the company's incident-management procedures.&lt;/p&gt;
&lt;h2&gt;
  
  
  3.2 What should you do first?
&lt;/h2&gt;

&lt;p&gt;Before executing troubleshooting commands:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Acknowledge the ticket.&lt;/li&gt;
&lt;li&gt;Identify the affected application and environment.&lt;/li&gt;
&lt;li&gt;Determine the reported symptoms and business impact.&lt;/li&gt;
&lt;li&gt;Check whether there is an active incident bridge or incident commander.&lt;/li&gt;
&lt;li&gt;Review recent deployments and infrastructure changes.&lt;/li&gt;
&lt;li&gt;Start with safe, read-only diagnostic commands.&lt;/li&gt;
&lt;li&gt;Communicate your investigation status.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not immediately restart applications, delete Pods, or modify production configuration without understanding the situation and following company procedures.&lt;/p&gt;
&lt;h2&gt;
  
  
  3.3 Your first Slack message
&lt;/h2&gt;

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

&lt;p&gt;Hi team,&lt;/p&gt;

&lt;p&gt;I have acknowledged INC-2026-1042 regarding failed requests to the Restaurant backend service.&lt;/p&gt;

&lt;p&gt;I am reviewing the Kubernetes Deployment, Pod readiness, Service configuration, and backend endpoints to determine the cause.&lt;/p&gt;

&lt;p&gt;I will provide another update within 10 minutes.&lt;/p&gt;

&lt;p&gt;Please let me know if there were any recent application deployments or infrastructure changes.&lt;/p&gt;

&lt;p&gt;Thank you.&lt;/p&gt;
&lt;h2&gt;
  
  
  3.4 What information should you collect?
&lt;/h2&gt;

&lt;p&gt;Before troubleshooting, identify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application name.&lt;/li&gt;
&lt;li&gt;Namespace.&lt;/li&gt;
&lt;li&gt;Cluster.&lt;/li&gt;
&lt;li&gt;Environment.&lt;/li&gt;
&lt;li&gt;Time the issue started.&lt;/li&gt;
&lt;li&gt;User-facing symptoms.&lt;/li&gt;
&lt;li&gt;Error codes, if available.&lt;/li&gt;
&lt;li&gt;Recent deployments.&lt;/li&gt;
&lt;li&gt;Monitoring alerts.&lt;/li&gt;
&lt;li&gt;Relevant logs.&lt;/li&gt;
&lt;li&gt;Current incident owner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For our lab:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application:&lt;/strong&gt; Restaurant Company\&lt;br&gt;
&lt;strong&gt;Namespace:&lt;/strong&gt; jumptotech-lab\&lt;br&gt;
&lt;strong&gt;Deployment:&lt;/strong&gt; restaurant\&lt;br&gt;
&lt;strong&gt;Service:&lt;/strong&gt; restaurant-service\&lt;br&gt;
&lt;strong&gt;Port:&lt;/strong&gt; 80\&lt;br&gt;
&lt;strong&gt;Replicas:&lt;/strong&gt; 2&lt;/p&gt;


&lt;h1&gt;
  
  
  PART 4 — BUILD YOUR KUBERNETES ENVIRONMENT FROM ZERO
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Step 1 — Verify Kubernetes access
&lt;/h2&gt;

&lt;p&gt;Open your terminal.&lt;/p&gt;

&lt;p&gt;If you are using Amazon EKS, make sure your AWS credentials, cluster access, and kubeconfig are configured.&lt;/p&gt;

&lt;p&gt;If you are using kind or minikube, ensure your local cluster is running.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl cluster-info
kubectl get nodes &lt;span class="nt"&gt;-o&lt;/span&gt; wide
kubectl config current-context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Kubernetes API Server is reachable.&lt;/li&gt;
&lt;li&gt;At least one Node is Ready.&lt;/li&gt;
&lt;li&gt;Your current context points to the intended lab cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Never assume you are connected to the correct cluster. Always verify your Kubernetes context before making changes.&lt;/p&gt;

&lt;p&gt;If you receive a connection error, stop and troubleshoot cluster access before continuing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Create your project directory
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/jumptotech-k8s-network-lab
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/jumptotech-k8s-network-lab
&lt;span class="nb"&gt;pwd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — Create a Namespace
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get namespaces
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Interview question: Why do we use Kubernetes Namespaces?&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Namespaces provide logical separation of namespaced Kubernetes resources within a cluster. Teams commonly use them to organize applications and environments, apply access controls, and manage resource quotas.&lt;/p&gt;

&lt;p&gt;Namespaces alone are not a complete security boundary.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 5 — CREATE THE RESTAURANT DEPLOYMENT
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 4 — Create deployment.yaml
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;cat &amp;gt; deployment.yaml &amp;lt;&amp;lt;'EOF'&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;restaurant&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jumptotech-lab&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;restaurant&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;restaurant&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.27&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50m"&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;64Mi"&lt;/span&gt;
          &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;250m"&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;128Mi"&lt;/span&gt;
        &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
          &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
          &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5 — Apply the Deployment
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check rollout status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl rollout status deployment/restaurant &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check resources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployments &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab

kubectl get replicasets &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Deployment exists.&lt;/li&gt;
&lt;li&gt;ReplicaSet exists.&lt;/li&gt;
&lt;li&gt;Two Restaurant Pods are Running and Ready.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the Pods are not Ready, do not continue blindly.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe deployment restaurant &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab

kubectl describe pods &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;restaurant

kubectl get events &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--sort-by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.lastTimestamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6 — Understand what happened
&lt;/h2&gt;

&lt;p&gt;When you executed &lt;code&gt;kubectl apply -f deployment.yaml&lt;/code&gt;, you submitted the desired application configuration to Kubernetes.&lt;/p&gt;

&lt;p&gt;The API Server processed the request.&lt;/p&gt;

&lt;p&gt;The Deployment Controller managed the ReplicaSet.&lt;/p&gt;

&lt;p&gt;The ReplicaSet Controller created the required Pods.&lt;/p&gt;

&lt;p&gt;The Scheduler selected Worker Nodes.&lt;/p&gt;

&lt;p&gt;kubelet worked with the container runtime to start the containers.&lt;/p&gt;

&lt;p&gt;The CNI implementation configured networking for the Pods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Student questions:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is a Deployment?&lt;/li&gt;
&lt;li&gt;What is a ReplicaSet?&lt;/li&gt;
&lt;li&gt;What is a Pod?&lt;/li&gt;
&lt;li&gt;Who selects the Worker Node?&lt;/li&gt;
&lt;li&gt;Who starts the container?&lt;/li&gt;
&lt;li&gt;What is the role of the Linux Kernel?&lt;/li&gt;
&lt;li&gt;Why does the Pod need a network interface and IP address?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Be prepared to explain every answer without reading your notes.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 6 — CREATE THE KUBERNETES SERVICE
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 7 — Create service.yaml
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; service.yaml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
apiVersion: v1
kind: Service
metadata:
  name: restaurant-service
  namespace: jumptotech-lab
spec:
  type: ClusterIP
  selector:
    app: restaurant
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab

kubectl describe svc restaurant-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check EndpointSlices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslices &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; kubernetes.io/service-name&lt;span class="o"&gt;=&lt;/span&gt;restaurant-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 8 — Understand Service and Pod labels
&lt;/h2&gt;

&lt;p&gt;Your Service has this selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;restaurant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Pods have this label:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;restaurant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The matching labels allow the EndpointSlice Controller to publish the correct backend endpoints.&lt;/p&gt;

&lt;p&gt;The Service provides a stable virtual IP address, called a ClusterIP.&lt;/p&gt;

&lt;p&gt;Pods can be replaced and receive new IP addresses, while the Service can retain its ClusterIP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interview question: Why do we need a Service if Pods already have IP addresses?&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Pod IP addresses may change when Pods are recreated. A Kubernetes Service provides a stable endpoint and Service discovery mechanism for reaching eligible backend Pods.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 7 — CREATE A DIAGNOSTIC CLIENT POD
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 9 — Create client.yaml
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; client.yaml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
apiVersion: v1
kind: Pod
metadata:
  name: client
  namespace: jumptotech-lab
spec:
  containers:
  - name: netshoot
    image: nicolaka/netshoot:latest
    command: ["sleep", "36000"]
    resources:
      requests:
        cpu: "25m"
        memory: "32Mi"
      limits:
        cpu: "200m"
        memory: "128Mi"
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; client.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Ready &lt;span class="se"&gt;\&lt;/span&gt;
  pod/client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter the Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;--&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your terminal prompt should change to something similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;client:~#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; You are now inside the Client Pod, not on your EC2 management host.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 8 — INVESTIGATE POD NETWORKING
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 10 — Check the Pod hostname
&lt;/h2&gt;

&lt;p&gt;Inside Client Pod:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 11 — Check network interfaces
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip addr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find the &lt;code&gt;eth0&lt;/code&gt; interface and its IPv4 address.&lt;/p&gt;

&lt;p&gt;Record the IP address.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 12 — Check routing
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ip route
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for the default route.&lt;/p&gt;

&lt;p&gt;In AWS VPC CNI, you may see a gateway such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default via 169.254.1.1 dev eth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other Kubernetes network implementations may have different routing configurations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 13 — Check DNS configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Identify the configured DNS server and search domains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interview question: What is a Linux Network Namespace?&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;A Network Namespace provides an isolated view of networking resources, including network interfaces, IP addresses, routing tables, and ports.&lt;/p&gt;

&lt;p&gt;Containers in the same Kubernetes Pod normally share one Network Namespace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interview question: What does CNI do?&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;The CNI implementation configures networking for Pods. Depending on the plugin, this includes network interfaces, IP addresses, and routing.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 9 — TRACE AN HTTP REQUEST
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 14 — DNS resolution
&lt;/h2&gt;

&lt;p&gt;Still inside Client Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup restaurant-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup restaurant-service.jumptotech-lab.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The DNS lookup returns the ClusterIP assigned to &lt;code&gt;restaurant-service&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Record the IP address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happened?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Client Pod's resolver queried cluster DNS.&lt;/p&gt;

&lt;p&gt;CoreDNS resolved the Kubernetes Service name.&lt;/p&gt;

&lt;p&gt;The DNS response provided the Service IP address.&lt;/p&gt;

&lt;p&gt;CoreDNS does not forward the HTTP request itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 15 — Send HTTP request
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-v&lt;/span&gt; http://restaurant-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://restaurant-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected HTTP status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default NGINX welcome page should be returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 16 — Understand the complete internal request flow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Client Pod initiates an HTTP request.&lt;/li&gt;
&lt;li&gt;DNS resolves &lt;code&gt;restaurant-service&lt;/code&gt; to its ClusterIP.&lt;/li&gt;
&lt;li&gt;The client establishes a TCP connection to the Service IP on port 80.&lt;/li&gt;
&lt;li&gt;The Kubernetes Service dataplane selects an eligible backend Pod.&lt;/li&gt;
&lt;li&gt;In iptables-based kube-proxy mode, Linux Netfilter applies Service forwarding and address translation rules.&lt;/li&gt;
&lt;li&gt;The packet reaches the selected Restaurant Pod.&lt;/li&gt;
&lt;li&gt;NGINX receives the HTTP request on port 80.&lt;/li&gt;
&lt;li&gt;NGINX returns the HTTP response.&lt;/li&gt;
&lt;li&gt;The response travels back to the Client Pod.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Important distinction:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;kube-proxy programs forwarding rules in its supported modes. In iptables mode, the Linux Kernel processes packets using those rules.&lt;/p&gt;

&lt;p&gt;The exact implementation depends on the cluster networking configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 17 — Compare direct Pod IP requests
&lt;/h2&gt;

&lt;p&gt;Exit the Client Pod:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Find the current Restaurant Pod IP addresses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;restaurant &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Record both Pod IPs.&lt;/p&gt;

&lt;p&gt;Enter Client Pod again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;--&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the following, replacing the placeholders with the real IP addresses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://POD_1_IP:80
curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://POD_2_IP:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if a Pod IP is &lt;code&gt;172.31.46.36&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://172.31.46.36:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Interview question: What is the difference between a Service request and a direct Pod IP request?&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;A Service request uses a stable Service endpoint and the cluster's Service routing implementation to reach an eligible backend.&lt;/p&gt;

&lt;p&gt;A direct Pod IP request targets one specific Pod and bypasses Service load balancing.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 10 — REPRODUCE THE PRODUCTION INCIDENT
&lt;/h1&gt;

&lt;p&gt;Now we will simulate a real Kubernetes networking incident.&lt;/p&gt;

&lt;p&gt;We will intentionally create a Service with an incorrect selector.&lt;/p&gt;

&lt;p&gt;We will not modify the healthy Restaurant Service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 18 — Exit Client Pod
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 19 — Create a broken Service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; broken-service.yaml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
apiVersion: v1
kind: Service
metadata:
  name: restaurant-broken
  namespace: jumptotech-lab
spec:
  type: ClusterIP
  selector:
    app: wrong-restaurant
  ports:
  - name: http
    port: 80
    targetPort: 80
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; broken-service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 20 — Investigate the broken Service
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe svc restaurant-broken &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check Pod labels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--show-labels&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check EndpointSlices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslices &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; kubernetes.io/service-name&lt;span class="o"&gt;=&lt;/span&gt;restaurant-broken &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The Service selector uses &lt;code&gt;app: wrong-restaurant&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Restaurant Pods use &lt;code&gt;app: restaurant&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because these values do not match, the Service has no eligible backend endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 21 — Reproduce the failed HTTP request
&lt;/h2&gt;

&lt;p&gt;Test DNS from Client Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;client &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  nslookup restaurant-broken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The DNS name should resolve to the broken Service's ClusterIP.&lt;/p&gt;

&lt;p&gt;Now test HTTP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;client &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  curl &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;--max-time&lt;/span&gt; 5 http://restaurant-broken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request should fail because the Service has no eligible backend endpoints.&lt;/p&gt;

&lt;p&gt;The exact failure may be connection refused, timeout, or another network-level error depending on the cluster dataplane.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not automatically describe this as HTTP 503.&lt;/strong&gt; A Service without endpoints does not necessarily return an HTTP response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 22 — Identify the root cause
&lt;/h2&gt;

&lt;p&gt;Compare:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service selector:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app: wrong-restaurant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pod label:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Root cause:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Kubernetes Service selector did not match the Restaurant Pod labels.&lt;/p&gt;

&lt;p&gt;As a result, no eligible backend endpoints were available for that Service.&lt;/p&gt;

&lt;p&gt;The application Pods were healthy, but traffic could not reach them through the broken Service.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 11 — COMMUNICATE YOUR FINDINGS
&lt;/h1&gt;

&lt;p&gt;Before applying the fix, write an investigation update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Slack message:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi team,&lt;/p&gt;

&lt;p&gt;I identified a likely root cause for INC-2026-1042.&lt;/p&gt;

&lt;p&gt;The Restaurant application Pods are Running and Ready, but the affected Kubernetes Service has no eligible backend endpoints.&lt;/p&gt;

&lt;p&gt;The Service selector is configured with &lt;code&gt;app: wrong-restaurant&lt;/code&gt;, while the application Pods use &lt;code&gt;app: restaurant&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I reproduced the connectivity failure from a diagnostic Pod.&lt;/p&gt;

&lt;p&gt;I am preparing a selector correction and will verify the backend endpoints and HTTP response after the change.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 12 — FIX THE INCIDENT
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 23 — Correct the Service selector
&lt;/h2&gt;

&lt;p&gt;For our isolated lab, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch svc restaurant-broken &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"selector":{"app":"restaurant"}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In real production, follow change authorization and GitOps procedures. If the Service is managed through Git, Helm, or Argo CD, update the source of truth to prevent the incorrect configuration from returning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 24 — Verify the fix
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe svc restaurant-broken &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check EndpointSlices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslices &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; kubernetes.io/service-name&lt;span class="o"&gt;=&lt;/span&gt;restaurant-broken &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm that backend Pod IPs appear.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;client &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  curl &lt;span class="nt"&gt;-I&lt;/span&gt; &lt;span class="nt"&gt;--max-time&lt;/span&gt; 5 http://restaurant-broken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 25 — Verify the original healthy Service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;client &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  curl &lt;span class="nt"&gt;-I&lt;/span&gt; &lt;span class="nt"&gt;--max-time&lt;/span&gt; 5 http://restaurant-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a real production incident, one successful curl is not enough to establish full recovery.&lt;/p&gt;

&lt;p&gt;You should also verify monitoring metrics, error rates, readiness, backend health, and the actual user-facing path.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 13 — RESOLUTION COMMUNICATION
&lt;/h1&gt;

&lt;p&gt;After verifying recovery, write a resolution update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Slack message:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi team,&lt;/p&gt;

&lt;p&gt;INC-2026-1042 has been resolved in our lab environment.&lt;/p&gt;

&lt;p&gt;Root cause: The Kubernetes Service selector did not match the application Pod labels, leaving the Service without eligible backend endpoints.&lt;/p&gt;

&lt;p&gt;Actions taken:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confirmed the application Pods were Running and Ready.&lt;/li&gt;
&lt;li&gt;Reviewed Service configuration and Pod labels.&lt;/li&gt;
&lt;li&gt;Inspected EndpointSlices.&lt;/li&gt;
&lt;li&gt;Reproduced the failed HTTP request from a diagnostic Pod.&lt;/li&gt;
&lt;li&gt;Corrected the Service selector.&lt;/li&gt;
&lt;li&gt;Verified backend endpoints were populated.&lt;/li&gt;
&lt;li&gt;Confirmed HTTP 200 responses after the fix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I recommend adding automated validation for Service selectors and backend endpoint availability to help prevent similar configuration errors.&lt;/p&gt;

&lt;p&gt;I will document the investigation and resolution in the incident ticket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Only use this resolution message after completing and verifying the corresponding actions.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 14 — COMPLETE YOUR INCIDENT TICKET
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Incident Report
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Incident ID:&lt;/strong&gt; INC-2026-1042&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application:&lt;/strong&gt; Restaurant Company&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment:&lt;/strong&gt; Kubernetes Lab&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Backend Service connectivity failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Simulated inability to reach the backend application through the affected Service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detection:&lt;/strong&gt; Simulated monitoring alert and failed HTTP connectivity test.&lt;/p&gt;

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

&lt;p&gt;Reviewed Kubernetes Deployment, Pod status, Service configuration, Pod labels, and EndpointSlices.&lt;/p&gt;

&lt;p&gt;Confirmed the application Pods were Running and Ready.&lt;/p&gt;

&lt;p&gt;Observed that the affected Service did not have eligible backend endpoints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root Cause:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Service selector mismatch.&lt;/p&gt;

&lt;p&gt;The Service used &lt;code&gt;app: wrong-restaurant&lt;/code&gt;, while the Pods used &lt;code&gt;app: restaurant&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Updated the Service selector to match the Pod labels.&lt;/p&gt;

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

&lt;p&gt;Confirmed backend endpoints appeared and the Service returned HTTP 200 from the diagnostic Client Pod.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preventive Actions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add deployment validation for Service selectors.&lt;/li&gt;
&lt;li&gt;Monitor Service backend availability.&lt;/li&gt;
&lt;li&gt;Review Kubernetes manifests before deployment.&lt;/li&gt;
&lt;li&gt;Use GitOps and peer-reviewed changes where applicable.&lt;/li&gt;
&lt;li&gt;Maintain clear incident runbooks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Status:&lt;/strong&gt; Resolved — after successful verification.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 15 — BONUS LAB: KUBERNETES SELF-HEALING
&lt;/h1&gt;

&lt;p&gt;This lab demonstrates how Kubernetes maintains the desired number of Pods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 26 — Check existing Pods
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;restaurant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 27 — Delete one Pod
&lt;/h2&gt;

&lt;p&gt;Choose an actual Restaurant Pod name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod POD_NAME &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;POD_NAME&lt;/code&gt; with the real name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 28 — Watch Kubernetes create a replacement
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;-w&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press Ctrl+C when the new Pod becomes Ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 29 — Verify replicas
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment restaurant &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected: Two Ready replicas after recovery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interview question: What happens when a Pod is deleted?&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;The ReplicaSet Controller detects that the number of existing Pods is below the desired replica count and creates a replacement Pod.&lt;/p&gt;

&lt;p&gt;The Scheduler assigns the new Pod to a suitable Node, and kubelet starts its containers.&lt;/p&gt;

&lt;p&gt;This is an example of Kubernetes reconciliation and self-healing.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 16 — BONUS LAB: ACCESS THE APPLICATION FROM A BROWSER
&lt;/h1&gt;

&lt;p&gt;From the machine where kubectl is configured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  svc/restaurant-service &lt;span class="se"&gt;\&lt;/span&gt;
  8080:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Expected: NGINX welcome page.&lt;/p&gt;

&lt;p&gt;If kubectl is running on a remote EC2 instance, &lt;code&gt;localhost:8080&lt;/code&gt; refers to that EC2 instance, not your laptop. Use an approved SSH tunnel or another authorized access method if you need to view it locally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Port-forwarding is a diagnostic tool. It does not demonstrate the production AWS ALB and Ingress request path.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 17 — UNDERSTAND THE EXTERNAL HTTP REQUEST FLOW
&lt;/h1&gt;

&lt;p&gt;A real customer usually does not access the application's internal Kubernetes Service name.&lt;/p&gt;

&lt;p&gt;Consider a production architecture using AWS ALB.&lt;/p&gt;

&lt;p&gt;A typical request flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Customer opens the Restaurant Company website.&lt;/li&gt;
&lt;li&gt;The browser resolves the public domain through DNS.&lt;/li&gt;
&lt;li&gt;The browser connects to the public application endpoint, commonly over HTTPS.&lt;/li&gt;
&lt;li&gt;AWS ALB receives the request.&lt;/li&gt;
&lt;li&gt;ALB evaluates listener and routing rules.&lt;/li&gt;
&lt;li&gt;The request is forwarded to a configured target group.&lt;/li&gt;
&lt;li&gt;The target group sends the request to a healthy backend target.&lt;/li&gt;
&lt;li&gt;The application processes the request.&lt;/li&gt;
&lt;li&gt;The HTTP response returns to the browser.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With AWS Load Balancer Controller, ALB can target Pod IPs directly in IP target mode or NodePorts in instance target mode.&lt;/p&gt;

&lt;p&gt;For a separate internal backend call, a frontend server Pod may resolve a Kubernetes Service name using CoreDNS and send traffic through the internal Service dataplane.&lt;/p&gt;

&lt;p&gt;A browser-hosted React application may instead call a public backend API through ALB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You must know which architecture your application actually uses.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Important HTTP status codes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;What DevOps investigates&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;OK&lt;/td&gt;
&lt;td&gt;Successful response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;201&lt;/td&gt;
&lt;td&gt;Created&lt;/td&gt;
&lt;td&gt;Resource creation succeeded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;301 / 302&lt;/td&gt;
&lt;td&gt;Redirect&lt;/td&gt;
&lt;td&gt;Redirect configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;Bad Request&lt;/td&gt;
&lt;td&gt;Invalid request or API validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;Unauthorized&lt;/td&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;403&lt;/td&gt;
&lt;td&gt;Forbidden&lt;/td&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;404&lt;/td&gt;
&lt;td&gt;Not Found&lt;/td&gt;
&lt;td&gt;Missing route or resource&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;Internal Server Error&lt;/td&gt;
&lt;td&gt;Application/backend failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;502&lt;/td&gt;
&lt;td&gt;Bad Gateway&lt;/td&gt;
&lt;td&gt;Gateway or upstream response failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;503&lt;/td&gt;
&lt;td&gt;Service Unavailable&lt;/td&gt;
&lt;td&gt;Backend availability or overload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;504&lt;/td&gt;
&lt;td&gt;Gateway Timeout&lt;/td&gt;
&lt;td&gt;Upstream timeout&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; A 404 does not necessarily mean the entire application is unavailable. A 400 does not automatically mean the application is down. HTTP status codes must be interpreted in context.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 18 — HOW TO TROUBLESHOOT DIFFERENT ERRORS
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Scenario A — Pod is Pending
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pod POD_NAME &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Investigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Insufficient CPU or memory.&lt;/li&gt;
&lt;li&gt;Scheduling constraints.&lt;/li&gt;
&lt;li&gt;Node availability.&lt;/li&gt;
&lt;li&gt;Taints and tolerations.&lt;/li&gt;
&lt;li&gt;Persistent volume requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scenario B — ImagePullBackOff
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pod POD_NAME &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Investigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incorrect image name.&lt;/li&gt;
&lt;li&gt;Missing image tag.&lt;/li&gt;
&lt;li&gt;Registry access.&lt;/li&gt;
&lt;li&gt;Image pull permissions.&lt;/li&gt;
&lt;li&gt;Registry connectivity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scenario C — CrashLoopBackOff
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs POD_NAME &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="nt"&gt;--previous&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also inspect Pod events and container exit codes.&lt;/p&gt;

&lt;p&gt;Investigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application startup failure.&lt;/li&gt;
&lt;li&gt;Incorrect configuration.&lt;/li&gt;
&lt;li&gt;Missing dependencies.&lt;/li&gt;
&lt;li&gt;Resource limits.&lt;/li&gt;
&lt;li&gt;Probe failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scenario D — Service DNS resolution fails
&lt;/h2&gt;

&lt;p&gt;Check from a diagnostic Pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nslookup restaurant-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Investigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service existence.&lt;/li&gt;
&lt;li&gt;Namespace and DNS name.&lt;/li&gt;
&lt;li&gt;CoreDNS health.&lt;/li&gt;
&lt;li&gt;Pod DNS configuration.&lt;/li&gt;
&lt;li&gt;DNS connectivity and network policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scenario E — DNS works but HTTP fails
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslices &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; jumptotech-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--show-labels&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Investigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service selector.&lt;/li&gt;
&lt;li&gt;Pod readiness.&lt;/li&gt;
&lt;li&gt;Target port.&lt;/li&gt;
&lt;li&gt;Application listener.&lt;/li&gt;
&lt;li&gt;Network policies.&lt;/li&gt;
&lt;li&gt;Service dataplane behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scenario F — External users receive 503
&lt;/h2&gt;

&lt;p&gt;Investigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS ALB target health.&lt;/li&gt;
&lt;li&gt;Ingress configuration.&lt;/li&gt;
&lt;li&gt;Target groups.&lt;/li&gt;
&lt;li&gt;Service and endpoint availability.&lt;/li&gt;
&lt;li&gt;Pod readiness.&lt;/li&gt;
&lt;li&gt;Application health checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The investigation depends on which component generated the 503.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 19 — HOW TO ANSWER IN A DEVOPS INTERVIEW
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Interview Question 1: Tell me about yourself
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sample answer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I am building hands-on experience in DevOps and cloud infrastructure, focusing on Linux, AWS, Docker, Kubernetes, Terraform, and CI/CD automation.&lt;/p&gt;

&lt;p&gt;Through my Restaurant Company project, I have practiced deploying containerized applications to Kubernetes, configuring Deployments and Services, troubleshooting Pod networking, and investigating application connectivity issues.&lt;/p&gt;

&lt;p&gt;I have also worked on simulated production incidents, where I followed a structured process to identify problems, verify fixes, and communicate technical findings.&lt;/p&gt;

&lt;p&gt;I am especially interested in cloud infrastructure automation, Kubernetes operations, and production reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview Question 2: Explain how an application gets deployed to Kubernetes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sample answer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a typical CI/CD workflow, developers push their code to GitHub, which triggers an automated pipeline.&lt;/p&gt;

&lt;p&gt;The pipeline builds and tests the application, creates a Docker image, and pushes it to a container registry such as Amazon ECR.&lt;/p&gt;

&lt;p&gt;The deployment process updates the Kubernetes Deployment with the new image version.&lt;/p&gt;

&lt;p&gt;The Kubernetes API Server accepts the desired configuration, and the Deployment Controller manages the rollout through ReplicaSets.&lt;/p&gt;

&lt;p&gt;The Scheduler assigns new Pods to suitable Worker Nodes, and kubelet works with the container runtime to start the containers.&lt;/p&gt;

&lt;p&gt;The CNI implementation configures Pod networking, and readiness probes help determine when the application is ready to receive traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview Question 3: Explain how an HTTP request reaches a Kubernetes application
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sample answer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For an external request, the client first resolves the public domain through DNS and connects to the application's public endpoint.&lt;/p&gt;

&lt;p&gt;In an AWS environment, the request may reach an Application Load Balancer.&lt;/p&gt;

&lt;p&gt;The ALB evaluates its listener rules and forwards traffic to a healthy backend target.&lt;/p&gt;

&lt;p&gt;For internal communication between Kubernetes applications, a client Pod can use the backend Service DNS name.&lt;/p&gt;

&lt;p&gt;CoreDNS resolves the Service name to its ClusterIP.&lt;/p&gt;

&lt;p&gt;The Kubernetes Service dataplane then forwards the connection to an eligible backend Pod.&lt;/p&gt;

&lt;p&gt;The application processes the HTTP request and sends the response back to the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview Question 4: Tell me about a Kubernetes incident you resolved
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sample answer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;During my DevOps training, I investigated a simulated production incident involving a Restaurant Company application running in Kubernetes.&lt;/p&gt;

&lt;p&gt;The application Pods were healthy, but HTTP requests through a Kubernetes Service were failing.&lt;/p&gt;

&lt;p&gt;I started by reviewing Pod readiness, the Service configuration, Pod labels, and EndpointSlices.&lt;/p&gt;

&lt;p&gt;I reproduced the connectivity failure from a diagnostic Client Pod.&lt;/p&gt;

&lt;p&gt;DNS resolution was successful, which helped me separate DNS issues from Service routing problems.&lt;/p&gt;

&lt;p&gt;I found that the Service selector did not match the application Pod labels, leaving the Service without eligible backend endpoints.&lt;/p&gt;

&lt;p&gt;I corrected the selector, verified that the expected endpoints appeared, and confirmed the application returned HTTP 200.&lt;/p&gt;

&lt;p&gt;I also practiced communicating the incident status, documenting the root cause, and recommending preventive checks.&lt;/p&gt;

&lt;p&gt;This exercise helped me understand how Kubernetes networking works and how to approach connectivity issues systematically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview Question 5: How do you troubleshoot a Kubernetes application that is unavailable?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sample answer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I first confirm the scope and impact of the issue.&lt;/p&gt;

&lt;p&gt;I check monitoring alerts and determine whether the problem affects all users or only specific requests.&lt;/p&gt;

&lt;p&gt;Then I inspect the Kubernetes Deployment, Pod readiness, events, and application logs.&lt;/p&gt;

&lt;p&gt;If the Pods are healthy, I investigate Service configuration, EndpointSlices, DNS resolution, and network connectivity.&lt;/p&gt;

&lt;p&gt;For externally exposed applications, I also check Ingress configuration, load balancer target health, and relevant AWS networking components.&lt;/p&gt;

&lt;p&gt;Once I identify the likely root cause, I coordinate the appropriate mitigation, verify recovery, monitor for recurrence, and document the incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview Question 6: What is the difference between CoreDNS, CNI, and kube-proxy?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sample answer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CoreDNS provides DNS resolution for Kubernetes Service names.&lt;/p&gt;

&lt;p&gt;CNI is the interface through which the networking implementation configures Pod connectivity, including IP addressing and interfaces.&lt;/p&gt;

&lt;p&gt;kube-proxy, when used, implements Kubernetes Service networking by programming forwarding rules based on Service and EndpointSlice information.&lt;/p&gt;

&lt;p&gt;These components have different responsibilities, but they work together to support communication between Kubernetes applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview Question 7: How do you communicate during a production incident?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sample answer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I acknowledge the incident and confirm the business impact.&lt;/p&gt;

&lt;p&gt;I provide regular updates to the incident channel, including what has been verified, what I am investigating, and when the next update is expected.&lt;/p&gt;

&lt;p&gt;I avoid presenting assumptions as confirmed root causes.&lt;/p&gt;

&lt;p&gt;If the incident requires escalation or a potentially disruptive change, I coordinate with the incident lead and relevant teams.&lt;/p&gt;

&lt;p&gt;After service recovery, I document the root cause, resolution, verification results, and preventive actions.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 20 — YOUR FINAL HOMEWORK
&lt;/h1&gt;

&lt;p&gt;Submit the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Screenshot showing Kubernetes Nodes in Ready status.&lt;/li&gt;
&lt;li&gt;Screenshot showing your Restaurant Deployment and two Ready Pods.&lt;/li&gt;
&lt;li&gt;Screenshot showing your Kubernetes Service and ClusterIP.&lt;/li&gt;
&lt;li&gt;Screenshot showing the EndpointSlices.&lt;/li&gt;
&lt;li&gt;Screenshot showing successful CoreDNS resolution.&lt;/li&gt;
&lt;li&gt;Screenshot showing HTTP 200 from the healthy Service.&lt;/li&gt;
&lt;li&gt;Screenshot showing the broken Service selector.&lt;/li&gt;
&lt;li&gt;Screenshot showing missing backend endpoints.&lt;/li&gt;
&lt;li&gt;Screenshot showing the failed HTTP request.&lt;/li&gt;
&lt;li&gt;Screenshot showing the corrected selector.&lt;/li&gt;
&lt;li&gt;Screenshot showing HTTP 200 after the fix.&lt;/li&gt;
&lt;li&gt;Your first Slack incident acknowledgment.&lt;/li&gt;
&lt;li&gt;Your investigation update.&lt;/li&gt;
&lt;li&gt;Your resolution update.&lt;/li&gt;
&lt;li&gt;Your completed incident report.&lt;/li&gt;
&lt;li&gt;A written or recorded interview explanation of the incident.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final practical assessment
&lt;/h2&gt;

&lt;p&gt;Your instructor may ask you to share your screen and demonstrate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to find a Deployment.&lt;/li&gt;
&lt;li&gt;How to check Pod health.&lt;/li&gt;
&lt;li&gt;How to find the Pod IP.&lt;/li&gt;
&lt;li&gt;How to inspect a Service.&lt;/li&gt;
&lt;li&gt;How to inspect EndpointSlices.&lt;/li&gt;
&lt;li&gt;How to check DNS resolution.&lt;/li&gt;
&lt;li&gt;How to test HTTP connectivity.&lt;/li&gt;
&lt;li&gt;How to identify a selector mismatch.&lt;/li&gt;
&lt;li&gt;How to correct the configuration.&lt;/li&gt;
&lt;li&gt;How to verify recovery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should explain what every command does and why you are using it.&lt;/p&gt;




&lt;h1&gt;
  
  
  PART 21 — CLEANUP
&lt;/h1&gt;

&lt;p&gt;After your instructor confirms that the assignment is complete, remove the lab resources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete namespace jumptotech-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This removes the resources created in that Namespace.&lt;/p&gt;

&lt;p&gt;Do not run this command until you have saved your screenshots and completed the assignment.&lt;/p&gt;




&lt;h1&gt;
  
  
  FINAL MESSAGE TO STUDENTS
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Your goal is not to memorize Kubernetes commands. Your goal is to understand the full lifecycle of an application and how to troubleshoot it when something goes wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A strong DevOps Engineer should be able to explain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How application code moves from GitHub to Kubernetes.&lt;/li&gt;
&lt;li&gt;How Kubernetes schedules and runs containers.&lt;/li&gt;
&lt;li&gt;How Pods receive network connectivity.&lt;/li&gt;
&lt;li&gt;How Services and EndpointSlices support application communication.&lt;/li&gt;
&lt;li&gt;How DNS resolution differs from HTTP routing.&lt;/li&gt;
&lt;li&gt;How an HTTP request reaches an application.&lt;/li&gt;
&lt;li&gt;How to investigate a production incident safely.&lt;/li&gt;
&lt;li&gt;How to communicate findings and progress.&lt;/li&gt;
&lt;li&gt;How to verify that a problem is resolved.&lt;/li&gt;
&lt;li&gt;How to explain the work clearly in a technical interview.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember the incident response structure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact → Investigation → Evidence → Root Cause → Mitigation → Verification → Communication → Prevention&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Practice explaining your project in your own words.&lt;/p&gt;

&lt;p&gt;Be clear about which activities you performed in a lab and which tools or processes belong to the example production architecture. Never present a training exercise as actual employment experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JumpToTech DevOps Bootcamp — Learn It. Build It. Troubleshoot It. Explain It.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can copy this entire handbook directly into your student group or development platform. It includes the complete lab, the simulated ticket, step-by-step commands, workplace communication, incident reporting, and interview preparation.&lt;/p&gt;

</description>
      <category>sre</category>
      <category>kubernetes</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
    <item>
      <title>JumpToTech DevOps/SRE Bootcamp Production Incident Response Lab — Banking Application on AWS EKS</title>
      <dc:creator>Aisalkyn Aidarova</dc:creator>
      <pubDate>Wed, 28 Oct 2026 21:17:39 +0000</pubDate>
      <link>https://dev.to/jumptotech/jumptotech-devopssre-bootcampproduction-incident-response-lab-banking-application-on-aws-eks-26l6</link>
      <guid>https://dev.to/jumptotech/jumptotech-devopssre-bootcampproduction-incident-response-lab-banking-application-on-aws-eks-26l6</guid>
      <description>&lt;p&gt;&lt;strong&gt;Kubernetes Incident Response — Banking Application on AWS EKS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the most critical incidents I handled involved a customer-facing banking application running on AWS EKS.&lt;/p&gt;

&lt;p&gt;Our production environment had approximately &lt;strong&gt;60 frontend replicas distributed across three Availability Zones&lt;/strong&gt;, with an AWS Application Load Balancer handling incoming traffic. We used Prometheus and Grafana for monitoring and alerting.&lt;/p&gt;

&lt;p&gt;During a production release, we started receiving alerts that the banking application's HTTP 5xx error rate had increased significantly. The error rate reached approximately &lt;strong&gt;18%&lt;/strong&gt;, and customers were experiencing intermittent failures when accessing their accounts.&lt;/p&gt;

&lt;p&gt;I was the primary SRE responsible for investigating the incident and coordinating the technical recovery.&lt;/p&gt;

&lt;p&gt;My first step was to assess the impact. I checked Grafana dashboards for error rates, request latency, and available replicas. I noticed that available frontend replicas had dropped from &lt;strong&gt;60 to 38&lt;/strong&gt;, which explained why the remaining Pods were struggling to handle traffic.&lt;/p&gt;

&lt;p&gt;I then checked the EKS cluster using &lt;code&gt;kubectl get nodes&lt;/code&gt;, &lt;code&gt;kubectl get pods&lt;/code&gt;, and &lt;code&gt;kubectl get deployments&lt;/code&gt;. All worker nodes were healthy, so I ruled out a cluster-wide infrastructure failure.&lt;/p&gt;

&lt;p&gt;When I inspected the affected Pods using &lt;code&gt;kubectl describe pod&lt;/code&gt;, I found repeated readiness-probe failures. The new containers were Running, but they were not becoming Ready.&lt;/p&gt;

&lt;p&gt;I checked the Kubernetes events and application logs and found that the readiness probes were returning &lt;strong&gt;HTTP 404&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After comparing the new deployment configuration with the previous release, I identified the root cause: the readiness probe had been changed from &lt;code&gt;/&lt;/code&gt; to &lt;code&gt;/healthz&lt;/code&gt;, but the application did not expose the new endpoint.&lt;/p&gt;

&lt;p&gt;I also found that the deployment configuration allowed too many healthy Pods to become unavailable during the rollout, which contributed to the loss of serving capacity.&lt;/p&gt;

&lt;p&gt;At that point, my priority was restoring service rather than troubleshooting the defective release further.&lt;/p&gt;

&lt;p&gt;I rolled back the deployment using &lt;code&gt;kubectl rollout undo deployment/banking-frontend&lt;/code&gt; and monitored the recovery using &lt;code&gt;kubectl rollout status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As the previous application version came back online, available replicas increased from &lt;strong&gt;38 to 60&lt;/strong&gt;, and the HTTP 5xx error rate returned to its normal baseline.&lt;/p&gt;

&lt;p&gt;I verified recovery by checking Kubernetes Service endpoints, application health checks, load balancer metrics, and Grafana dashboards.&lt;/p&gt;

&lt;p&gt;The application was restored within approximately &lt;strong&gt;12 minutes&lt;/strong&gt; of incident detection.&lt;/p&gt;

&lt;p&gt;After the incident, I completed a root cause analysis and recommended three improvements: automated readiness-probe validation in CI/CD, safer RollingUpdate settings with &lt;code&gt;maxUnavailable: 0&lt;/code&gt;, and canary deployments to detect faulty releases before they affect the entire application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The outcome was that I restored full application availability, reduced the immediate customer impact, and helped establish deployment safeguards to prevent the same failure from recurring.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This incident reinforced the importance of understanding Kubernetes readiness probes, deployment strategies, monitoring, and rapid rollback procedures in a high-availability banking environment.&lt;/p&gt;

&lt;p&gt;Numbers in this example&lt;br&gt;
Metric  Value&lt;br&gt;
Frontend replicas   60&lt;br&gt;
Availability Zones  3&lt;br&gt;
Available replicas during incident  38&lt;br&gt;
Unavailable replicas    22&lt;br&gt;
Peak HTTP 5xx error rate    18%&lt;br&gt;
Readiness-probe error   HTTP 404&lt;br&gt;
Recovery time   12 minutes&lt;br&gt;
Replicas after recovery 60&lt;br&gt;
Recovery method Kubernetes rollback&lt;/p&gt;

&lt;p&gt;These numbers form a consistent hypothetical production incident, not a historical incident verified at JPMorgan Chase. In a real interview, students should use the metrics from their own incident evidence rather than present these figures as their personal employment history.&lt;/p&gt;

&lt;p&gt;What makes this a senior-level answer: It demonstrates that the engineer assessed customer impact, distinguished application failure from infrastructure failure, investigated Kubernetes events and logs, identified the configuration defect, performed a controlled rollback, verified recovery, and implemented preventive measures.&lt;br&gt;
Student Lab Guide · Day 2&lt;/p&gt;

&lt;p&gt;Scenario: Banking Application Outage After a Failed Production Deployment\&lt;br&gt;
Environment: AWS EKS, Kubernetes, Prometheus, Grafana, NGINX\&lt;br&gt;
Role: DevOps / Site Reliability Engineer\&lt;br&gt;
Difficulty: Intermediate\&lt;br&gt;
Estimated duration: 3 hours\&lt;br&gt;
Incident severity: Simulated SEV-2 / P2&lt;/p&gt;
&lt;h3&gt;
  
  
  Important note for students
&lt;/h3&gt;

&lt;p&gt;This lab uses a fictional banking incident inspired by the types of production problems that can occur in large financial institutions such as JPMorgan Chase. It is not a documented incident at Chase, and you must not claim that you worked at Chase or resolved this incident in its actual production environment.&lt;/p&gt;

&lt;p&gt;You will, however, perform a real hands-on investigation in your own Kubernetes cluster. You can discuss that experience confidently in interviews as an independently resolved production-style lab incident.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Your role and responsibilities
&lt;/h2&gt;

&lt;p&gt;You are a DevOps/SRE Engineer supporting a banking application running on Amazon EKS.&lt;/p&gt;

&lt;p&gt;The application allows customers to access banking services. Your team is responsible for keeping the infrastructure reliable, deploying application releases, monitoring service health, and restoring service when an incident occurs.&lt;/p&gt;

&lt;p&gt;During this lab, you are responsible for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Monitoring: Detect when application availability decreases.&lt;/li&gt;
&lt;li&gt;Incident response: Assess the impact and prioritize recovery.&lt;/li&gt;
&lt;li&gt;Troubleshooting: Investigate Deployments, ReplicaSets, Pods, Services, probes, events, and logs.&lt;/li&gt;
&lt;li&gt;Mitigation: Restore the last known healthy application version.&lt;/li&gt;
&lt;li&gt;Verification: Confirm application availability and healthy Kubernetes status.&lt;/li&gt;
&lt;li&gt;Communication: Provide clear updates to the incident commander and application team.&lt;/li&gt;
&lt;li&gt;Root cause analysis: Explain why the failure occurred and how to prevent recurrence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your objective is not simply to restart a Pod. Your objective is to restore customer-facing service safely, understand the failure, and reduce the chance of recurrence.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. The incident you will investigate
&lt;/h2&gt;

&lt;p&gt;INC-2026-001&lt;/p&gt;

&lt;p&gt;Simulated SEV-2&lt;/p&gt;
&lt;h2&gt;
  
  
  Banking frontend unavailable after a Kubernetes deployment
&lt;/h2&gt;

&lt;p&gt;Business impact: Customers may be unable to access the banking frontend during the failed rollout.&lt;/p&gt;

&lt;p&gt;Technical symptoms: Deployment unavailable, Pods not Ready, application health checks failing.&lt;/p&gt;

&lt;p&gt;Expected root cause: A newly released application version fails its readiness checks.&lt;/p&gt;

&lt;p&gt;Recovery strategy: Roll back to the previous known-good Deployment revision.&lt;/p&gt;
&lt;h3&gt;
  
  
  What happened?
&lt;/h3&gt;

&lt;p&gt;The development team released a new version of the banking frontend.&lt;/p&gt;

&lt;p&gt;The new container starts, but a configuration defect causes its HTTP readiness endpoint to fail. Kubernetes therefore cannot mark the new Pods as Ready.&lt;/p&gt;

&lt;p&gt;As the rollout progresses, the old working Pods are replaced. Eventually, the application has no Ready endpoints, and customers cannot access the service.&lt;/p&gt;

&lt;p&gt;Prometheus detects the decrease in available replicas. Grafana displays the outage and can trigger an alert.&lt;/p&gt;

&lt;p&gt;You are the engineer responsible for diagnosing the failure and restoring the previous working release.&lt;/p&gt;
&lt;h3&gt;
  
  
  What success looks like
&lt;/h3&gt;

&lt;p&gt;At the end of the incident:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Deployment is restored to its previous healthy revision.&lt;/li&gt;
&lt;li&gt;Two frontend replicas are Ready.&lt;/li&gt;
&lt;li&gt;The Kubernetes Service has healthy endpoints.&lt;/li&gt;
&lt;li&gt;The application returns &lt;code&gt;HTTP 200&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Monitoring shows recovery.&lt;/li&gt;
&lt;li&gt;You have recorded the root cause, commands, evidence, and preventive actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not invent recovery times, financial losses, customer counts, or performance improvements. Measure your actual lab results and use those numbers in your interview explanation.&lt;/p&gt;
&lt;h1&gt;
  
  
  3. Understand the production architecture
&lt;/h1&gt;

&lt;p&gt;Banking customers&lt;/p&gt;

&lt;p&gt;Customer requests&lt;/p&gt;

&lt;p&gt;Application access layer&lt;/p&gt;

&lt;p&gt;Production would typically use HTTPS and an ALB or Ingress&lt;/p&gt;

&lt;p&gt;Kubernetes Service&lt;/p&gt;

&lt;p&gt;banking-service · ClusterIP · Port 80&lt;/p&gt;

&lt;p&gt;Frontend Pod 1&lt;/p&gt;

&lt;p&gt;NGINX · Port 80&lt;/p&gt;

&lt;p&gt;Frontend Pod 2&lt;/p&gt;

&lt;p&gt;NGINX · Port 80&lt;/p&gt;

&lt;p&gt;Prometheus collects Kubernetes health metrics. Grafana visualizes them and evaluates alert rules.&lt;/p&gt;

&lt;p&gt;In this lab, the frontend is represented by an NGINX container. It is not a complete banking system with authentication, payment processing, or a database. The incident concerns the frontend availability layer.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Lab prerequisites
&lt;/h2&gt;

&lt;p&gt;From the previous lesson, you should already have:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Expected state&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;EKS cluster&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worker nodes&lt;/td&gt;
&lt;td&gt;Ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Namespace&lt;/td&gt;
&lt;td&gt;&lt;code&gt;banking-incident-lab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;banking-frontend&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replicas&lt;/td&gt;
&lt;td&gt;2/2 Ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;td&gt;&lt;code&gt;banking-service&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prometheus&lt;/td&gt;
&lt;td&gt;Running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grafana&lt;/td&gt;
&lt;td&gt;Running&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use the same cluster and namespace as yesterday. Do not delete or reinstall the monitoring stack.&lt;/p&gt;
&lt;h1&gt;
  
  
  Part A — Establish the healthy production baseline
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Step 1. Verify your AWS and Kubernetes environment
&lt;/h2&gt;

&lt;p&gt;Run these commands on the machine where your &lt;code&gt;kubectl&lt;/code&gt; is configured.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl config current-context

kubectl get nodes &lt;span class="nt"&gt;-o&lt;/span&gt; wide

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring

kubectl get deployment &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="nt"&gt;-o&lt;/span&gt; wide

kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected Deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME               READY   UP-TO-DATE   AVAILABLE
banking-frontend   2/2     2            2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Student task: Explain why &lt;code&gt;READY 2/2&lt;/code&gt; matters and how Kubernetes determines whether a Pod is ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2. Inspect the readiness probe
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Readiness: http-get http://:80/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The readiness probe is configured to request &lt;code&gt;/&lt;/code&gt; on port &lt;code&gt;80&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The kubelet runs the probe. Successful HTTP responses (status codes 200–399) allow the container to become Ready.&lt;/p&gt;

&lt;p&gt;A failed readiness probe does not necessarily restart the container. Instead, the Pod becomes Not Ready and is excluded from normal Service traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3. Verify the Service endpoints
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslice &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; kubernetes.io/service-name&lt;span class="o"&gt;=&lt;/span&gt;banking-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpoints banking-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see two Pod addresses associated with the Service.&lt;/p&gt;

&lt;p&gt;The EndpointSlice output is the preferred way to inspect endpoint readiness in modern Kubernetes. The legacy Endpoints command is included because it is still common in interviews and older runbooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4. Verify the application responds
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run baseline-client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curlimages/curl:8.11.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--command&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"HTTP %{http_code}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-time&lt;/span&gt; 10 &lt;span class="se"&gt;\&lt;/span&gt;
  http://banking-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;HTTP 200
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A temporary warning about attaching to the diagnostic Pod is acceptable if the curl command still returns HTTP 200.&lt;/p&gt;

&lt;p&gt;Evidence to save: Terminal output showing two Ready replicas and a successful HTTP response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5. Save the healthy Deployment configuration
&lt;/h2&gt;

&lt;p&gt;This is an essential production habit: preserve the current state before making changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/banking-incident-lab/evidence

kubectl get deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/banking-incident-lab/evidence/deployment-before.yaml

kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deployment/banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not manually edit the saved baseline file during the incident.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part B — Configure Prometheus and Grafana
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 6. Open Grafana
&lt;/h2&gt;

&lt;p&gt;Use the Grafana instance you configured in the previous lesson.&lt;/p&gt;

&lt;p&gt;If Grafana is not accessible, start the port-forward on the management machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring &lt;span class="se"&gt;\&lt;/span&gt;
  svc/monitoring-grafana &lt;span class="se"&gt;\&lt;/span&gt;
  3000:80 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--address&lt;/span&gt; 127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you access Grafana through an EC2 management machine, use your existing SSH tunnel to reach its localhost port securely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7. Create a production monitoring dashboard
&lt;/h2&gt;

&lt;p&gt;In Grafana, go to Dashboards → New → New dashboard → Add visualization and select your Prometheus data source.&lt;/p&gt;

&lt;p&gt;Create these four panels.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Panel&lt;/th&gt;
&lt;th&gt;Visualization&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Available replicas&lt;/td&gt;
&lt;td&gt;Stat&lt;/td&gt;
&lt;td&gt;Number of available frontend replicas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desired replicas&lt;/td&gt;
&lt;td&gt;Stat&lt;/td&gt;
&lt;td&gt;Number Kubernetes should maintain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unavailable replicas&lt;/td&gt;
&lt;td&gt;Stat&lt;/td&gt;
&lt;td&gt;Detect loss of Deployment availability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Container restarts&lt;/td&gt;
&lt;td&gt;Time series&lt;/td&gt;
&lt;td&gt;Track application restarts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Panel 1 — Available replicas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;kube_deployment_status_replicas_available&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-frontend"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Healthy value: &lt;code&gt;2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Panel 2 — Desired replicas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;kube_deployment_spec_replicas&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-frontend"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Healthy value: &lt;code&gt;2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Panel 3 — Unavailable replicas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;kube_deployment_spec_replicas&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-frontend"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;
&lt;span class="n"&gt;kube_deployment_status_replicas_available&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-frontend"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Healthy value: &lt;code&gt;0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Panel 4 — Container restarts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;kube_pod_container_status_restarts_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="na"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;=~&lt;/span&gt;&lt;span class="s2"&gt;"banking-frontend-.*"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Healthy initial value: normally &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Save the dashboard as:&lt;/p&gt;

&lt;p&gt;JumpToTech — Banking Production Incident Monitoring&lt;/p&gt;

&lt;p&gt;If a query returns No Data, verify the Prometheus data source, kube-state-metrics, namespace, and Deployment labels before proceeding. Do not treat missing metrics as a healthy result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8. Create an incident alert
&lt;/h2&gt;

&lt;p&gt;Navigate to Alerting → Alert rules → New alert rule.&lt;/p&gt;

&lt;p&gt;Configure:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alert name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BankingFrontendUnavailable&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data source&lt;/td&gt;
&lt;td&gt;Prometheus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluation interval&lt;/td&gt;
&lt;td&gt;1 minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pending period&lt;/td&gt;
&lt;td&gt;1 minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Condition&lt;/td&gt;
&lt;td&gt;Last value greater than 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Severity label&lt;/td&gt;
&lt;td&gt;&lt;code&gt;warning&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Folder&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Banking Production Lab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notification&lt;/td&gt;
&lt;td&gt;Your configured email contact point&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use this PromQL expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;kube_deployment_spec_replicas&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-frontend"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;
&lt;span class="n"&gt;kube_deployment_status_replicas_available&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-incident-lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"banking-frontend"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the alert condition to Last IS ABOVE 0. Depending on your Grafana version, this may require a Reduce expression and a Threshold expression.&lt;/p&gt;

&lt;p&gt;Use these annotations:&lt;/p&gt;

&lt;p&gt;Summary: Banking frontend has unavailable replicas.&lt;/p&gt;

&lt;p&gt;Description: The banking-frontend Deployment has fewer available replicas than desired. Investigate Pod readiness, Deployment rollout status, Kubernetes events, and Service endpoints.&lt;/p&gt;

&lt;p&gt;For the lab, use &lt;code&gt;No Data = No Data&lt;/code&gt; and &lt;code&gt;Error = Error&lt;/code&gt; so that missing metrics or evaluation failures are not silently treated as healthy. These states should be monitored separately in a real production alerting design.&lt;/p&gt;

&lt;p&gt;Before proceeding, verify the alert is saved and that the email contact point is selected by the notification policy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part C — Simulate the production incident
&lt;/h1&gt;

&lt;p&gt;Controlled incident simulation&lt;/p&gt;

&lt;p&gt;The next commands deliberately make the banking frontend unavailable. Execute them only in your dedicated training namespace, never in a real production banking environment.&lt;/p&gt;

&lt;p&gt;Verify that &lt;code&gt;kubectl config current-context&lt;/code&gt; points to your training cluster before continuing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9. Understand the failure before creating it
&lt;/h2&gt;

&lt;p&gt;Our healthy NGINX container responds to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /
HTTP 200 OK
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will introduce a bad readiness probe that requests a nonexistent endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /healthz
HTTP 404 Not Found
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NGINX will still be running, but the kubelet will mark the container Not Ready.&lt;/p&gt;

&lt;p&gt;To make the full outage reproducible, we will temporarily use the Deployment's &lt;code&gt;Recreate&lt;/code&gt; strategy. This intentionally removes the old Pods before starting replacements. This is not a recommended production rollout strategy for a high-availability banking frontend.&lt;/p&gt;

&lt;p&gt;This combination demonstrates two failures: a bad health-check configuration and a rollout strategy that allows total service interruption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 10. Record the incident start time
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; +&lt;span class="s2"&gt;"Incident started: %Y-%m-%dT%H:%M:%SZ"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Record the output in your incident worksheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 11. Configure the controlled rollout strategy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;merge &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"strategy":{"type":"Recreate","rollingUpdate":null}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This changes the rollout strategy without changing the application template.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.strategy.type}{"\n"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 12. Introduce the faulty readiness probe
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;strategic &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"template":{"spec":{"containers":[{"name":"frontend","readinessProbe":{"httpGet":{"path":"/healthz","port":80},"initialDelaySeconds":5,"periodSeconds":5}}]}}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a new Deployment revision with a bad readiness endpoint.&lt;/p&gt;

&lt;p&gt;Wait approximately 30–60 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 13. Observe the production failure
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab

kubectl get deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab

kubectl rollout status deployment/banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected symptoms may resemble:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                                READY   STATUS
banking-frontend-xxxxxxxxxx-aaaaa   0/1     Running
banking-frontend-xxxxxxxxxx-bbbbb   0/1     Running
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME               READY   UP-TO-DATE   AVAILABLE
banking-frontend   0/2     2            0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rollout status command should time out because the new Pods never become available.&lt;/p&gt;

&lt;p&gt;Important: A Pod can have &lt;code&gt;STATUS Running&lt;/code&gt; while showing &lt;code&gt;READY 0/1&lt;/code&gt;. These fields describe different aspects of Pod health.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 14. Confirm customer-facing impact
&lt;/h2&gt;

&lt;p&gt;Inspect the endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get endpointslice &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; kubernetes.io/service-name&lt;span class="o"&gt;=&lt;/span&gt;banking-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ready&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now test the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run incident-client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curlimages/curl:8.11.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--command&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  curl &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;--max-time&lt;/span&gt; 10 &lt;span class="se"&gt;\&lt;/span&gt;
  http://banking-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected: the request fails or times out because the Service has no Ready backend endpoints.&lt;/p&gt;

&lt;p&gt;The exact network error can vary with the cluster networking implementation.&lt;/p&gt;

&lt;p&gt;Record the actual error. Do not assume every failed Service request returns HTTP 503.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part D — Investigate like a production SRE
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 15. Establish the scope
&lt;/h2&gt;

&lt;p&gt;First determine whether the problem affects only the banking application or the whole Kubernetes cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="nt"&gt;-o&lt;/span&gt; wide

kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; monitoring

kubectl get deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are Worker Nodes Ready?&lt;/li&gt;
&lt;li&gt;Are Prometheus and Grafana healthy?&lt;/li&gt;
&lt;li&gt;Are the banking Pods Running?&lt;/li&gt;
&lt;li&gt;Are the banking Pods Ready?&lt;/li&gt;
&lt;li&gt;Is the issue isolated to the frontend?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not immediately restart every Pod. That can destroy useful evidence without fixing the underlying configuration problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 16. Examine Kubernetes events
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get events &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--sort-by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.lastTimestamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for an event resembling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Warning  Unhealthy  Readiness probe failed:
HTTP probe failed with statuscode: 404
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a strong clue that the application is running but failing its health check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 17. Describe the affected Pods
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pods &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;banking-frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find the &lt;code&gt;Readiness&lt;/code&gt; field and the &lt;code&gt;Events&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;You should observe that the probe is requesting &lt;code&gt;/healthz&lt;/code&gt; instead of &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 18. Examine application logs
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for NGINX requests to &lt;code&gt;/healthz&lt;/code&gt; returning HTTP 404.&lt;/p&gt;

&lt;p&gt;This is the evidence that connects the Kubernetes probe failures to the application endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 19. Compare the deployment revisions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deployment/banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect the live readiness configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.template.spec.containers[0].readinessProbe.httpGet.path}{"\n"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;Compare it with the baseline configuration saved before the incident, where the path was &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Root cause analysis
&lt;/h3&gt;

&lt;p&gt;Primary configuration defect&lt;/p&gt;

&lt;p&gt;The new Deployment revision used &lt;code&gt;/healthz&lt;/code&gt; as its readiness endpoint, but the NGINX application did not serve that path.&lt;/p&gt;

&lt;p&gt;Failure mechanism&lt;/p&gt;

&lt;p&gt;Kubelet received HTTP 404, marked the new Pods Not Ready, and the Service had no Ready endpoints.&lt;/p&gt;

&lt;p&gt;Outage-enabling rollout configuration&lt;/p&gt;

&lt;p&gt;The intentionally selected &lt;code&gt;Recreate&lt;/code&gt; strategy removed the healthy old Pods before the replacement Pods passed readiness checks.&lt;/p&gt;

&lt;p&gt;Business impact in the simulation&lt;/p&gt;

&lt;p&gt;The banking frontend became unavailable to clients using its Kubernetes Service.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part E — Recover production service
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 20. Perform a Kubernetes rollback
&lt;/h2&gt;

&lt;p&gt;We have identified the defective Deployment revision. Rather than manually editing the new release during the outage, restore the previous working version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl rollout undo deployment/banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the recovery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl rollout status deployment/banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deployment "banking-frontend" successfully rolled out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Deployment rollback restores the previous Pod template. It does not automatically restore the Deployment's rollout strategy, so we must correct that separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 21. Restore the safer RollingUpdate strategy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;merge &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"strategy":{"type":"RollingUpdate","rollingUpdate":{"maxSurge":"25%","maxUnavailable":"25%"}}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With two replicas, this configuration allows a surge Pod while rounding the permitted unavailable count down to zero during normal rolling updates.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.strategy.type}{"\n"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 22. Verify recovery
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab

kubectl get deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab

kubectl get endpointslice &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; kubernetes.io/service-name&lt;span class="o"&gt;=&lt;/span&gt;banking-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Deployment should return to &lt;code&gt;2/2&lt;/code&gt; available.&lt;/p&gt;

&lt;p&gt;Verify the readiness endpoint was restored:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment banking-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.template.spec.containers[0].readinessProbe.httpGet.path}{"\n"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;Finally, test the Service again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run recovery-client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; banking-incident-lab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curlimages/curl:8.11.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--command&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"HTTP %{http_code}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-time&lt;/span&gt; 10 &lt;span class="se"&gt;\&lt;/span&gt;
  http://banking-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;HTTP 200
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 23. Record the recovery time
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; +&lt;span class="s2"&gt;"Service restored: %Y-%m-%dT%H:%M:%SZ"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calculate the elapsed time between the incident start and recovery.&lt;/p&gt;

&lt;p&gt;This is your measured lab recovery duration. It is not automatically the same as production MTTR, which is typically calculated across multiple incidents.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part F — Verify monitoring and notification
&lt;/h1&gt;

&lt;p&gt;Return to the JumpToTech — Banking Production Incident Monitoring dashboard.&lt;/p&gt;

&lt;p&gt;The expected pattern is:&lt;/p&gt;

&lt;p&gt;Illustrative availability timeline&lt;/p&gt;

&lt;p&gt;Example only. Replace these values with observations from your Grafana dashboard.&lt;/p&gt;

&lt;p&gt;Desired replicasAvailable replicas&lt;/p&gt;

&lt;p&gt;00.511.52HealthyFailureInvestigationRollbackRecovered&lt;/p&gt;

&lt;p&gt;Check whether the alert transitioned through its expected states:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Normal → Pending → Firing → Resolved&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Because alert evaluations run periodically, a short outage may not last long enough to enter &lt;code&gt;Firing&lt;/code&gt;. If no alert fired, record that observation rather than claiming that an email was sent.&lt;/p&gt;

&lt;p&gt;If an email was delivered, preserve the timestamp and alert name as evidence.&lt;/p&gt;

&lt;h1&gt;
  
  
  Part G — Your incident report
&lt;/h1&gt;

&lt;p&gt;Every student must complete this worksheet using their own terminal outputs and observations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Incident report — INC-2026-001
&lt;/h2&gt;

&lt;p&gt;Complete after the hands-on exercise. Copy the report into your lab submission.&lt;/p&gt;

&lt;p&gt;Engineer name&lt;/p&gt;

&lt;p&gt;Incident start time (UTC)&lt;/p&gt;

&lt;p&gt;How was the incident detected?&lt;/p&gt;

&lt;p&gt;Observed application impact&lt;/p&gt;

&lt;p&gt;Key commands and evidence&lt;/p&gt;

&lt;p&gt;Root cause&lt;/p&gt;

&lt;p&gt;Mitigation and recovery actions&lt;/p&gt;

&lt;p&gt;Service restoration time (UTC)&lt;/p&gt;

&lt;p&gt;Measured recovery duration&lt;/p&gt;

&lt;p&gt;Preventive actions&lt;/p&gt;

&lt;p&gt; Copy completed incident report&lt;/p&gt;

&lt;h2&gt;
  
  
  Prevention recommendations
&lt;/h2&gt;

&lt;p&gt;A strong SRE does more than restore service. They identify engineering improvements.&lt;/p&gt;

&lt;p&gt;For this incident, recommend:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add automated readiness-endpoint checks to the CI/CD pipeline before deployment.&lt;/li&gt;
&lt;li&gt;Use RollingUpdate with an appropriate availability budget for customer-facing applications.&lt;/li&gt;
&lt;li&gt;Test application health checks in staging before promoting to production.&lt;/li&gt;
&lt;li&gt;Monitor desired versus available replicas and alert on sustained unavailability.&lt;/li&gt;
&lt;li&gt;Introduce canary deployments or progressive delivery for high-risk releases.&lt;/li&gt;
&lt;li&gt;Maintain a documented rollback runbook and test it regularly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Part H — Interview preparation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The question interviewers may ask
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Tell me about a production incident you independently investigated and resolved. What was the impact, root cause, and outcome?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Sample answer in English
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Production-Style Incident Response — AWS EKS Banking Application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;During a hands-on production incident simulation, I was responsible for investigating and restoring a banking frontend application deployed on AWS EKS.&lt;/p&gt;

&lt;p&gt;The application was running with two replicas behind a Kubernetes ClusterIP Service. We used Prometheus and Grafana to monitor Deployment availability, Pod readiness, and container restarts.&lt;/p&gt;

&lt;p&gt;During a deployment, the frontend became unavailable. My initial investigation showed that the desired replica count was two, but zero replicas were available.&lt;/p&gt;

&lt;p&gt;I checked the Deployment rollout status, inspected the Pods, reviewed Kubernetes events, and examined the application logs.&lt;/p&gt;

&lt;p&gt;The containers were running, but their readiness probes were failing with HTTP 404 errors.&lt;/p&gt;

&lt;p&gt;I traced the issue to an incorrect readiness probe path introduced in the new Deployment revision. The application was configured to check &lt;code&gt;/healthz&lt;/code&gt;, but NGINX was only serving the root endpoint. The rollout also used a Recreate strategy, which removed the healthy Pods before the replacement Pods were ready.&lt;/p&gt;

&lt;p&gt;After identifying the root cause, I rolled back the Deployment to the previous working revision and restored the RollingUpdate strategy.&lt;/p&gt;

&lt;p&gt;I verified that both replicas returned to Ready, the Service had healthy endpoints, and the application responded with HTTP 200.&lt;/p&gt;

&lt;p&gt;The key lesson was that a running container does not necessarily mean the application is ready to serve traffic.&lt;/p&gt;

&lt;p&gt;To prevent recurrence, I recommended automated health-check validation in CI/CD, safer rollout strategies, and Prometheus/Grafana alerting for unavailable replicas.&lt;/p&gt;

&lt;p&gt;This exercise gave me practical experience in Kubernetes incident investigation, root cause analysis, rollback, service recovery, and production reliability practices.&lt;/p&gt;

&lt;p&gt;This is an interview practice script for a lab incident. Personalize it with your actual evidence and recovery time. Do not present the simulation as an incident you handled while employed by a bank.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow-up interview questions you must master
&lt;/h2&gt;

&lt;p&gt;12 technical interview questions&lt;/p&gt;

&lt;p&gt;Tap to reveal answers&lt;/p&gt;

&lt;p&gt;1.Why were the Pods Running but not Ready?&lt;/p&gt;

&lt;p&gt;2.What is the difference between readiness and liveness probes?&lt;/p&gt;

&lt;p&gt;3.Why didn't Kubernetes automatically fix the incident?&lt;/p&gt;

&lt;p&gt;4.What did the Service do when both Pods were Not Ready?&lt;/p&gt;

&lt;p&gt;5.Why did the deployment cause a full outage?&lt;/p&gt;

&lt;p&gt;6.Would the default RollingUpdate strategy behave the same way?&lt;/p&gt;

&lt;p&gt;7.Why use kubectl rollout undo?&lt;/p&gt;

&lt;p&gt;8.Did the rollback restore every Deployment setting?&lt;/p&gt;

&lt;p&gt;9.How did Prometheus detect the problem?&lt;/p&gt;

&lt;p&gt;10.What is the difference between mitigation and root cause analysis?&lt;/p&gt;

&lt;p&gt;11.What would you communicate to stakeholders?&lt;/p&gt;

&lt;p&gt;12.What is the most important prevention?&lt;/p&gt;

&lt;h1&gt;
  
  
  Part I — Student submission checklist
&lt;/h1&gt;

&lt;p&gt;Evidence and deliverables&lt;/p&gt;

&lt;p&gt;0/12 completed&lt;/p&gt;

&lt;p&gt;Deployment healthy before incident: 2/2&lt;/p&gt;

&lt;p&gt;Baseline application test: HTTP 200&lt;/p&gt;

&lt;p&gt;Grafana dashboard with banking metrics&lt;/p&gt;

&lt;p&gt;Screenshot showing failed readiness probes&lt;/p&gt;

&lt;p&gt;Kubernetes events showing HTTP 404&lt;/p&gt;

&lt;p&gt;Application logs showing failed /healthz requests&lt;/p&gt;

&lt;p&gt;Deployment rollout history&lt;/p&gt;

&lt;p&gt;Successful rollback output&lt;/p&gt;

&lt;p&gt;Deployment recovered: 2/2&lt;/p&gt;

&lt;p&gt;Application recovered: HTTP 200&lt;/p&gt;

&lt;p&gt;Incident report with measured recovery time&lt;/p&gt;

&lt;p&gt;Interview explanation practiced aloud&lt;/p&gt;

&lt;h2&gt;
  
  
  Final learning outcome
&lt;/h2&gt;

&lt;p&gt;By completing this lab, you should be able to explain the entire incident lifecycle:&lt;/p&gt;

&lt;p&gt;1&lt;/p&gt;

&lt;p&gt;Detect&lt;/p&gt;

&lt;p&gt;2&lt;/p&gt;

&lt;p&gt;Investigate&lt;/p&gt;

&lt;p&gt;3&lt;/p&gt;

&lt;p&gt;Mitigate&lt;/p&gt;

&lt;p&gt;4&lt;/p&gt;

&lt;p&gt;Verify&lt;/p&gt;

&lt;p&gt;5&lt;/p&gt;

&lt;p&gt;Prevent&lt;/p&gt;

&lt;p&gt;Your goal is not to memorize a fictional story. Your goal is to reproduce the failure, understand every command, independently restore the application, and explain your own results clearly in an interview.&lt;/p&gt;

&lt;p&gt;This is the difference between knowing Kubernetes commands and demonstrating practical DevOps/SRE incident-response skills.&lt;/p&gt;

&lt;p&gt;JumpToTech DevOps/SRE Bootcamp — Production Incident Response Lab, Day 2&lt;/p&gt;

</description>
      <category>sre</category>
      <category>aws</category>
      <category>kubernetes</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
