Ravindra BagaleCourses & study guides मराठी

Chapter 58: Docker Projects Part 2: AWS RDS, DynamoDB, S3, Reel Upload, Microservices, Queues, Logging, Monitoring and Cloud Deploys

58.15 Project 31: Capstone - an Instagram-style app end to end (build, scan, push, deploy, monitor)

Why: the problem

This is the last project. We join everything from the last 30 projects into one real product. Suppose we are building Reelgram, a small Instagram-style app for a college in Nashik. Students sign up, upload photos and short reels, follow friends and see a feed. A real company like Instagram does not only write code. Every change goes through the same road: build an image, test it, scan it for security holes, push it to a registry, deploy it without downtime, and watch it in dashboards. If any step is missing, trouble follows. No scan means a known hole goes live. No health check means a broken release takes the site down. No monitoring means users tell us about the outage before we know. In this capstone we build that whole road. Five services run in containers: web, api, worker, Postgres and Redis, with media in S3. GitHub Actions builds, tests and scans every commit with Trivy, pushes to ECR, and deploys to EC2 over SSH with a health check and rollback. Prometheus and Grafana watch it, and an alert fires when the upload queue gets too long.

What: every term in plain English

  • Capstone — One project that uses every skill from the course together.
  • Pipeline — The automatic road from git push to running in production.
  • Trivy — A free open-source scanner that finds known CVEs in images and misconfigurations in Dockerfiles.
  • SBOM — Software Bill of Materials. A list of every package inside the image.
  • Multi-stage build — Build tools stay in the first stage; the final image has only the app.
  • Feed — The list of posts from people you follow, newest first, cached in Redis.
  • Worker — A background container that makes thumbnails and converts reels with ffmpeg from a Redis queue.
  • Queue length — How many jobs are waiting. If it grows, workers are too slow or down.
  • Environment approval — A GitHub setting so production deploys wait for a human click.
Lay out the repo. Write good Dockerfiles. Run it locally. Build the pipeline. Deploy to EC2. Monitor and alert. Clean up.
From git push to a monitored, scanned, rolled-out Instagram-style app

How: step by step

  1. Lay out the repo. web, api, worker folders, compose files, ops scripts, workflow.
  2. Write good Dockerfiles. Multi-stage, non-root, health checks, small base images.
  3. Run it locally. docker compose up with MinIO in place of S3.
  4. Build the pipeline. Test, build, Trivy scan, SBOM, push to ECR.
  5. Deploy to EC2. docker context over SSH, pull the tag, health check, rollback.
  6. Monitor and alert. Prometheus, Grafana, cAdvisor, an alert on queue length.
  7. Clean up. Stack, EC2, ECR repos, bucket.

Architecture

git push main GitHub Actions build x3 (web, api, worker) tests inside the image Trivy scan + SBOM fail on HIGH/CRITICAL push to ECR by commit tag OIDC role, no keys approve -> deploy.sh over SSH health check, rollback EC2: web, api, worker x2, Postgres, Redis media in S3 Prometheus + Grafana + alerts queue length, restarts, api up
Reelgram capstone pipeline

Folder layout

reelgram/
  web/  api/  worker/
  compose.yaml  compose.prod.yaml  .env.example
  monitoring/prometheus.yml  monitoring/alerts.yml
  ops/deploy.sh  ops/cleanup.sh
  .github/workflows/release.yml

Example 1: Repo layout, Dockerfiles and the local stack

Goal. Repo layout, Dockerfiles and the local stack.

reelgram/tree.txt

reelgram/
  web/        React (Vite) -> nginx static, Dockerfile
  api/        Node.js Express: auth, posts, follow, feed, presigned upload URLs
  worker/     Python: thumbnails (Pillow) and reels (ffmpeg) from Redis queue
  compose.yaml           local: all services + MinIO + monitoring
  compose.prod.yaml      prod: images from ECR, real S3 via IAM role
  monitoring/prometheus.yml  monitoring/alerts.yml
  ops/deploy.sh  ops/cleanup.sh
  .github/workflows/release.yml

worker/Dockerfile

FROM python:3.12-slim AS base
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg \
 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY worker.py .
RUN useradd -r -u 10001 reel
USER reel
CMD ["python", "worker.py"]

compose.yaml

services:
  web:
    build: ./web
    ports: ["8080:80"]
    depends_on: [api]

  api:
    build: ./api
    environment:
      DATABASE_URL: postgresql://reel:${DB_PASSWORD}@db:5432/reelgram
      REDIS_URL: redis://redis:6379
      S3_ENDPOINT: http://minio:9000
      S3_BUCKET: reelgram-media
      JWT_SECRET: ${JWT_SECRET}
    depends_on:
      db: { condition: service_healthy }
      redis: { condition: service_started }
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:3000/healthz"]
      interval: 10s
      retries: 3

  worker:
    build: ./worker
    environment:
      REDIS_URL: redis://redis:6379
      S3_ENDPOINT: http://minio:9000
      S3_BUCKET: reelgram-media
    deploy: { replicas: 2 }

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: reel
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: reelgram
    volumes: [pg:/var/lib/postgresql/data]
    healthcheck: { test: ["CMD", "pg_isready", "-U", "reel"], interval: 5s, retries: 10 }

  redis:
    image: redis:7-alpine
    command: ["redis-server", "--appendonly", "yes"]
    volumes: [redis:/data]

  minio:
    image: minio/minio:latest
    command: server /data --console-address :9001
    ports: ["9001:9001"]
    environment:
      MINIO_ROOT_USER: ${MINIO_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD}
    volumes: [media:/data]

volumes: { pg: {}, redis: {}, media: {} }

What each line does

  • One repo, three images — web, api and worker each have their own Dockerfile and their own ECR repo.
  • ffmpeg only in the worker — The api image stays small. Heavy tools live only where they are needed.
  • useradd -r -u 10001 — The worker runs as a normal user with a fixed id, not root.
  • --no-install-recommends and rm lists — Smaller image and fewer packages for Trivy to complain about.
  • MinIO locally — MinIO speaks the S3 API, so the same code works with real S3 in production.
  • replicas: 2 for worker — Two workers share the queue. Reels are processed twice as fast.
  • Values from .env — DB_PASSWORD, JWT_SECRET and MinIO login come from a local .env that is in .gitignore.

Green output

$ cp .env.example .env && docker compose up -d --build
 Container reelgram-db-1      Healthy
 Container reelgram-api-1     Started
 Container reelgram-worker-1  Started
 Container reelgram-worker-2  Started
 Container reelgram-web-1     Started
$ curl -s -X POST localhost:8080/api/signup -H 'content-type: application/json' -d '{"user":"asha","password":"lab-only-pass"}'
{"id":1,"user":"asha"}
$ docker compose logs worker --tail 3
worker-1  | job 1 reel.mp4 -> 720p.mp4 + thumb.jpg in 4.2s
$ docker images --format '{{.Repository}} {{.Size}}' | grep reelgram
reelgram-web 49.1MB
reelgram-api 158MB
reelgram-worker 412MB

Expected result. The whole app runs on the laptop. A reel upload is converted by a worker and shows in the feed.

Example 2: The pipeline: test, build, scan with Trivy, SBOM, push to ECR, then deploy with approval

Goal. The pipeline: test, build, scan with Trivy, SBOM, push to ECR, then deploy with approval.

.github/workflows/release.yml

name: release
on:
  push:
    branches: [main]

permissions:
  contents: read
  id-token: write

env:
  REGION: ap-south-1
  REG: 123456789012.dkr.ecr.ap-south-1.amazonaws.com

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        svc: [web, api, worker]
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/reelgram-ci
          aws-region: ap-south-1
      - uses: aws-actions/amazon-ecr-login@v2
      - name: Build
        uses: docker/build-push-action@v6
        with:
          context: ${{ matrix.svc }}
          load: true
          tags: ${{ env.REG }}/reelgram-${{ matrix.svc }}:${{ github.sha }}
          cache-from: type=gha,scope=${{ matrix.svc }}
          cache-to: type=gha,mode=max,scope=${{ matrix.svc }}
      - name: Unit tests inside the image
        if: matrix.svc == 'api'
        run: docker run --rm ${{ env.REG }}/reelgram-api:${{ github.sha }} npm test
      - name: Trivy scan (fail on HIGH and CRITICAL)
        uses: aquasecurity/trivy-action@0.28.0
        with:
          image-ref: ${{ env.REG }}/reelgram-${{ matrix.svc }}:${{ github.sha }}
          severity: HIGH,CRITICAL
          ignore-unfixed: true
          exit-code: "1"
      - name: SBOM
        uses: anchore/sbom-action@v0
        with:
          image: ${{ env.REG }}/reelgram-${{ matrix.svc }}:${{ github.sha }}
          artifact-name: sbom-${{ matrix.svc }}.spdx.json
      - name: Push
        run: docker push ${{ env.REG }}/reelgram-${{ matrix.svc }}:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - name: SSH setup
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.PROD_SSH_KEY }}" > ~/.ssh/prod
          echo "${{ secrets.PROD_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
          printf "Host prod\n HostName ${{ vars.PROD_HOST }}\n User ubuntu\n IdentityFile ~/.ssh/prod\n" > ~/.ssh/config
      - name: Deploy with health check
        run: bash ops/deploy.sh ${{ github.sha }}

What each line does

  • id-token: write + role-to-assume — GitHub OIDC. CI gets short AWS credentials for one run. No AWS keys stored in GitHub at all.
  • matrix svc — Three images build in parallel with the same steps.
  • cache-from type=gha — Layer cache between runs. Second builds take seconds, not minutes.
  • Tests inside the image — We test the exact image we will ship.
  • Trivy exit-code 1 — A HIGH or CRITICAL fixable CVE fails the job, so the image is never pushed.
  • SBOM artifact — A package list saved with each run. When the next big CVE appears, we search it in minutes.
  • Push only after scan — ECR never receives an image that failed tests or scan.
  • environment: production — The deploy job waits for a reviewer click, set in repo Settings, Environments.
  • Secrets in GitHub — Only the SSH key and known_hosts. The key file is created inside the runner and gone after the run.

Green output

build (api)     Trivy: reelgram-api:4c1e9d0 (alpine 3.20)
                Total: 0 (HIGH: 0, CRITICAL: 0)
build (worker)  Trivy: reelgram-worker:4c1e9d0 (debian 12.7)
                Total: 1 (HIGH: 1, CRITICAL: 0)
                libexpat1 CVE-2024-45491 HIGH fixed in 2.5.0-1+deb12u1
                Error: Process completed with exit code 1.
# fix: add apt-get upgrade -y to the worker stage, push again
build (worker)  Total: 0 (HIGH: 0, CRITICAL: 0)
                pushed reelgram-worker:7ab22f3
deploy          Waiting for review: production
deploy          approved by ravi -> deploy.sh 7ab22f3 -> health: healthy

Expected result. A vulnerable image was stopped by the scan. After the fix, all three images were pushed and deployed with approval.

Example 3: Deploy with health check and rollback, then monitor and alert on the upload queue

Goal. Deploy with health check and rollback, then monitor and alert on the upload queue.

ops/deploy.sh

set -e
TAG=${1:?usage: deploy.sh TAG}
export TAG
C="docker --context prod compose -f compose.yaml -f compose.prod.yaml"
docker context inspect prod >/dev/null 2>&1 || docker context create prod --docker host=ssh://prod
PREV=$(docker --context prod inspect reelgram-api-1 --format '{{index .Config.Labels "app.tag"}}' 2>/dev/null || echo none)
echo "deploying $TAG (previous $PREV)"
$C pull api web worker
$C up -d --no-deps api web worker
for i in $(seq 1 20); do
  S=$(docker --context prod inspect reelgram-api-1 --format '{{.State.Health.Status}}')
  [ "$S" = healthy ] && { echo "health: healthy"; exit 0; }
  sleep 3
done
echo "unhealthy, rolling back to $PREV"
TAG=$PREV $C up -d --no-deps api web worker
exit 1

monitoring/alerts.yml

groups:
  - name: reelgram
    rules:
      - alert: UploadQueueTooLong
        expr: redis_list_length{key="reel_jobs"} > 50
        for: 5m
        labels: { severity: warning }
        annotations:
          summary: "More than 50 reels waiting for 5 minutes"
          action: "docker compose up -d --scale worker=4, then check worker logs"
      - alert: ApiDown
        expr: up{job="api"} == 0
        for: 1m
        labels: { severity: critical }
      - alert: ContainerRestarting
        expr: increase(container_restart_count{name=~"reelgram.*"}[10m]) > 3
        labels: { severity: warning }

ops/cleanup.sh

docker --context prod compose -f compose.yaml -f compose.prod.yaml down -v
docker context rm prod
for r in web api worker; do aws ecr delete-repository --repository-name reelgram-$r --force; done
aws s3 rm s3://reelgram-media-prod --recursive && aws s3 rb s3://reelgram-media-prod
echo "terminate the EC2 instance and delete the reelgram-ci IAM role"

What each line does

  • compose.prod.yaml — Sets image to ECR with ${TAG}, adds the label app.tag, removes MinIO, and uses real S3 through the EC2 instance role.
  • pull then up — Images are downloaded first, so the switch itself takes only seconds.
  • Health loop — 20 checks, 3 seconds apart. If the api is not healthy in a minute, the previous tag comes back.
  • redis_list_length — Comes from redis_exporter with the check-keys option set to reel_jobs. Add it next to cAdvisor from Project 27.
  • for: 5m — Short spikes do not wake anyone. Only a queue that stays long fires.
  • action annotation — The alert tells the on-call person exactly what to do first.
  • ContainerRestarting — A crash loop is caught even if the health check passes between crashes.

Green output

$ bash ops/deploy.sh 7ab22f3
deploying 7ab22f3 (previous 4c1e9d0)
 Container reelgram-api-1  Recreated
health: healthy
$ for i in $(seq 1 80); do curl -s -F reel=@clip.mp4 https://reelgram.example.in/api/reels >/dev/null; done
# Prometheus after 5 minutes:
ALERTS{alertname="UploadQueueTooLong", severity="warning"}  firing  value 74
$ docker --context prod compose -f compose.yaml -f compose.prod.yaml up -d --scale worker=4 --no-deps worker
# 6 minutes later the queue is 0 and the alert is resolved

Expected result. The release went live safely, the queue alert fired under load, and scaling the workers fixed it.

Every command, step by step (plain docker and Compose)

  1. Clone and start

    git clone ... && cd reelgram && cp .env.example .env && docker compose up -d --build
    

    What it does: Everything local.

    reelgram-api-1 Started
    
  2. Check sizes

    docker images | grep reelgram
    

    What it does: Compare the three images.

    reelgram-web 49.1MB
    
  3. Scan locally

    docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image --severity HIGH,CRITICAL reelgram-worker
    

    What it does: Same scan as CI.

    Total: 0
    
  4. Make an SBOM

    docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image --format spdx-json reelgram-api
    

    What it does: Package list.

    "spdxVersion": "SPDX-2.3"
    
  5. Create OIDC role

    Create IAM role reelgram-ci trusting token.actions.githubusercontent.com for your repo only
    

    What it does: No keys in GitHub.

    Role created
    
  6. Push to main

    git push origin main
    

    What it does: The workflow starts.

    release #12 queued
    
  7. Approve

    GitHub, Actions, the run, Review deployments, Approve
    

    What it does: Deploy job runs.

    approved
    
  8. Check site

    curl -s https://reelgram.example.in/healthz
    

    What it does: Live.

    ok
    
  9. Grafana

    Open port 3000 through an SSH tunnel: ssh -L 3000:localhost:3000 prod
    

    What it does: Dashboards without opening ports.

    Grafana login page
    
  10. Load test

    Upload 80 reels in a loop
    

    What it does: Queue grows.

    UploadQueueTooLong firing
    
  11. Scale workers

    compose up -d --scale worker=4 --no-deps worker
    

    What it does: Queue drains.

    alert resolved
    
  12. Clean up

    bash ops/cleanup.sh
    

    What it does: Remove everything.

    terminate the EC2 instance
    

When it is red 1

Error: Could not assume role with OIDC: Not authorized to perform sts:AssumeRoleWithWebIdentity

Cause. The IAM role trust policy does not match the repo or branch.

Fix, step by step

  1. Set the sub condition to repo:OWNER/reelgram:ref:refs/heads/main.
  2. Keep permissions id-token: write in the workflow.

When it is red 2

Total: 3 (HIGH: 2, CRITICAL: 1) ... Error: Process completed with exit code 1.

Cause. The base image has fixable CVEs.

Fix, step by step

  1. Update the base tag (for example node:20-alpine latest patch).
  2. Add apt-get upgrade or apk upgrade in the build stage, then rebuild.

When it is red 3

worker-1 | ffmpeg: error while loading shared libraries

Cause. ffmpeg was copied from a builder stage without its libraries.

Fix, step by step

  1. Install ffmpeg with apt in the final stage, as in our worker Dockerfile.

When it is red 4

api-1 | AccessDenied: s3:PutObject on reelgram-media-prod

Cause. The EC2 instance role does not allow the bucket.

Fix, step by step

  1. Add s3:PutObject and s3:GetObject on arn:aws:s3:::reelgram-media-prod/* to the instance role.

When it is red 5

Host key verification failed.

Cause. The CI runner does not know the server's SSH key.

Fix, step by step

  1. Save ssh-keyscan output of the server in the PROD_KNOWN_HOSTS secret. Do not turn off host checking.

When it is red 6

unhealthy, rolling back to 4c1e9d0

Cause. The new api failed its health check, usually a missing env var or DB migration.

Fix, step by step

  1. Read docker --context prod compose logs api --tail 50.
  2. Run migrations as a one-off container before deploy.

Practice tasks

Easy Task 1: Local run

Why: Compose.

What to do: Run all services locally and upload one reel.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
docker compose up -d --build

Easy Task 2: Sizes

Why: Images.

What to do: Find the biggest image and say why.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
docker images

Easy Task 3: Scan

Why: Trivy.

What to do: Scan the worker image locally.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
aquasec/trivy image reelgram-worker

Medium Task 4: Fix a CVE

Why: Base image.

What to do: Make the scan pass by updating the base image.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
apt-get upgrade -y

Medium Task 5: OIDC

Why: CI.

What to do: Create the reelgram-ci role limited to your repo's main branch.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
token.actions.githubusercontent.com

Medium Task 6: Pipeline

Why: Actions.

What to do: Push to main and approve the production deploy.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
environment: production

Medium Task 7: Rollback

Why: Deploy.

What to do: Release a tag with a broken health route and watch rollback.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
bash ops/deploy.sh BADTAG

Hard Task 8: Alert

Why: Prometheus.

What to do: Make UploadQueueTooLong fire and resolve it by scaling.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
--scale worker=4

Hard Task 9: Grow

Why: Cloud.

What to do: Move the api to ECS Fargate using Project 29.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
aws ecs update-service

Easy Task 10: Clean

Why: Bill.

What to do: Delete stack, ECR repos, bucket, role and EC2.

How:
  1. Use your laptop with Docker, a GitHub repository, one AWS account with a billing alarm, and one Ubuntu EC2 t3.medium.
  2. Reuse code from Project 20 (reel upload), Project 27 (monitoring) and Project 28 (deploy over SSH).
  3. Run the steps and compare with the solution. Always run the cleanup step.
Solution
bash ops/cleanup.sh

Homework: try at home

Make Reelgram production-grade: move Postgres to RDS and Redis to ElastiCache, run api and worker on ECS Fargate as in Project 29, sign images with cosign in the pipeline, and add a Grafana dashboard for p95 upload time.

Recap

  • A real product needs a full road: build, test, scan, push, deploy, monitor.
  • Small multi-stage non-root images are faster and safer.
  • Trivy in CI stops known CVEs before they reach the registry.
  • OIDC gives CI short AWS access with no stored keys.
  • Deploy by commit tag with a health check and automatic rollback.
  • Alert on symptoms users feel, like a long upload queue, with a clear first action.
  • Clean up every cloud resource after practice.

FAQ

Q. Is this enough for a real startup?

For the first thousands of users, yes. Later move the database and Redis to managed services and the apps to ECS or Kubernetes.

Q. Why not Kubernetes here?

The goal is the full Docker road. The Kubernetes chapters run the same images on a cluster.

Q. Can I use GitLab or Jenkins?

Yes. The steps are the same: build, test, trivy, push, ssh deploy.

Q. Why does Trivy fail on things I cannot fix?

We use ignore-unfixed, so only CVEs with a fix fail the build.

Q. How do I show this in my resume?

Link the repo, show the pipeline screenshot, the Grafana dashboard and the rollback test.

Q. How much does it cost?

One t3.medium for a few hours plus small S3 and ECR use: well under 1 USD if you clean up.

Q. What should I learn next?

Kubernetes with Helm, then GitOps with Argo CD, using these same images.

Interview questions

  1. Walk me through your CI/CD pipeline for containers.

    Model answer: Build per service, test inside the image, Trivy scan and SBOM, push by commit tag to ECR, approved deploy with health check and rollback, then monitoring.

  2. How do you keep vulnerable images out of production?

    Model answer: Scan in CI with a failing threshold, rebuild often on patched bases, and use minimal images.

  3. How do you avoid storing cloud keys in CI?

    Model answer: Use OIDC federation to assume a short-lived IAM role.

  4. How would you handle slow video processing?

    Model answer: Queue jobs in Redis, process with scalable worker containers, and alert on queue length.

  5. What do you monitor for a containerized app?

    Model answer: Up status, error rate and latency, restarts, CPU and memory per container, and business queues.

Quick quiz

Q1. Why scan before pushing, not after?

So a vulnerable image never reaches the registry or production.

Q2. How does CI get AWS access without keys?

GitHub OIDC with a role it can assume for one run.

Q3. What is an SBOM used for?

To know quickly which images contain a package when a new CVE appears.

Q4. What happens if the new api is unhealthy?

deploy.sh brings back the previous tag.

Q5. Which alert tells us workers are too slow?

UploadQueueTooLong on the Redis queue length.

Samajla ka?

Lab

  1. Use one free-tier AWS account and one t3.micro or t2.micro EC2 instance.
  2. Attach an IAM role to EC2 instead of putting keys in files.
  3. Set a billing alarm of 5 USD before you start.
  4. Delete RDS, buckets and tables in the cleanup step of each project.
  5. Write every command you typed in a notebook.

Practice task

Join the reel-upload app and the microservices shop behind one gateway and add Prometheus monitoring.

Ravindra Bagale's Tip

Cloud project interview madhe khup vichartat. Pan cleanup visru naka, nahitar mahinyachya shevti bill yeil.

In short

  • Containers reach AWS through an IAM role, not hard-coded keys.
  • Test locally first with DynamoDB Local or LocalStack, then use real AWS.
  • Slow work like video transcoding goes to a worker through a queue.
  • Always clean up cloud resources after practice.

Ravi Sir's Cards for this lesson

मराठी cards