Interview Prep Hub

Virtusa: DevOps Engineer (Golang)

Role shape: DevOps / Platform Engineer with mandatory Golang
Stated experience: 15+ years hands-on
Core stack: AWS, Kubernetes (EKS/ECS), Terraform, PostgreSQL/Aurora, DynamoDB, MongoDB, Kafka, Jenkins, GitLab CI, Docker, Spring Boot microservices, Python/Shell
Domain: Banking / financial services products
Nice-to-have: TOGAF, AWS Certified Solutions Architect, data architecture and AI/ML exposure

Read this first — the gap is real, and it is workable

This JD is not one job. It is two roles fused into one requisition: a hands-on DevOps/SRE (Terraform, EKS, pipelines, on-call, cost) and an enterprise architect(TOGAF, governance, standards, mentoring junior architects, regulatory awareness). Staffing firms write these when the client has not decided which one they want, or when one very senior person is expected to be both.

Against that, your documented profile is six years as a full-stack engineer — Go/Fiber, Node, PostgreSQL, Redis, Docker, Kafka, Next.js. Strong Go. Strong data and event-driven fundamentals. No production AWS, Terraform or EKS ownership. Pretending otherwise does not survive the first scenario question, because infra interviews are answered in specifics: which backend your state lived in, what broke during a node upgrade, what your RPO actually was.

So do not position as a 15-year DevOps architect. Position as a Go platform engineer moving into infrastructure, and make Go the reason to hire you: most DevOps candidates on this pipeline write Python and Bash and read Go badly. You write Go. Everything that runs a modern cluster — Kubernetes, Terraform, Docker, etcd, Prometheus, ArgoCD — is written in Go, and someone who can read and patch a controller is worth more than someone who can only apply YAML.

Two honest outcomes are both wins: they down-level you to the senior DevOps seat that actually exists, or they route you to a Go microservices seat on the same banking account. Either beats being screened out for a bluff.

Your one-paragraph opening for this JD

"I am a backend engineer with six years in Go — Fiber services, PostgreSQL, Redis, Kafka, Docker, running microservices behind a gateway in a fintech product. The part of this role I am strongest on is the software side of platform work: writing the Go services and the tooling, designing around idempotency and at-least-once delivery, database modelling and query work, and the event-driven pieces with Kafka. The part I am actively building is the cloud-operations depth — AWS at architecture level, Terraform and EKS. I have been studying and labbing those deliberately rather than claiming production years I do not have. If the seat needs fifteen years of hands-on AWS ownership I am not that person yet; if it needs someone who can own the Go platform services and grow into the infrastructure, that is exactly where I am."

Say this early. It buys you credibility for every claim you make afterwards, and it stops the interviewer from spending the hour hunting for the hole.

Decoding the JD — what each line is really testing

  1. "DevOps engineers mandatorily with Golang" — they have Go services in the estate, or they want tooling and operators written in Go rather than Bash. Expect real Go questions: concurrency, context, graceful shutdown, error handling, building small static binaries. This is your strongest ground. Do not let it pass in two minutes.
  2. "EC2, Lambda, Glue Jobs, S3, RDS" — the Glue mention is the tell. This is a banking data platform: S3 data lake, Glue crawlers and Spark ETL, RDS/Aurora as the system of record, Lambda for glue-code and event handling. Not a generic web stack.
  3. "Provisioning AWS infrastructure through Terraform" — they want state management, modules, and a plan/apply pipeline story, not terraform apply from a laptop.
  4. "EKS and ECS" — both, which means a mixed estate: legacy services on ECS Fargate, newer ones on EKS. Be ready to argue when each is correct.
  5. "RDS, Aurora, DynamoDB, MongoDB" + "24/7 availability" + "backup and disaster recovery" — the heart of the role. RTO/RPO, failover, PITR, cross-region. If you prepare one area deeply, make it this one.
  6. "Kafka for event-driven architectures" — you already have this. Your outbox, at-least-once and idempotent-consumer experience is directly relevant and is a genuinely senior conversation.
  7. "Spring Boot" — you are not being asked to write Java. You are being asked to operate JVM services: containerising them correctly, heap and cgroup settings, actuator health endpoints, GC pauses showing up as latency.
  8. "Performance, security, reliability, availability, observability, compliance" — these six words are the AWS Well-Architected pillars in disguise. Answer design questions by walking those axes explicitly; it signals you think in the vocabulary their architects use.
  9. "Mentor junior architects, enforce standards and governance" — the architect half. Prepare ADRs, golden paths, paved-road platform thinking, review gates.
  10. "Regulatory changes impacting banking" — in India: RBI data localisation, audit trails, change management, segregation of duties. Knowing the vocabulary is enough at interview stage.

Coverage map — what you have, what you must build

P0 will be tested in round one and you cannot fake it • P1 will come up and needs a credible answer • P2 bonus signal

JD requirementYour real evidenceGap to closePriority
Golang6 yrs, Fiber services, concurrency, production ownershipPractise DevOps-flavoured Go: client-go, operators, CLI tooling, pprofP0
DockerMulti-stage builds, compose, containerised Go and Node servicesDistroless/scratch, non-root, image scanning, size and layer disciplineP0
Kubernetes / EKSConceptual onlyHands-on: probes, HPA, PDB, rollouts, RBAC, IRSA, VPC CNI limitsP0
TerraformNone documentedState/locking, modules, workspaces, plan-in-CI, import, driftP0
AWS core (EC2, S3, RDS, Lambda, IAM, VPC)None documentedBuild one real VPC + EKS + RDS stack in a free-tier accountP0
PostgreSQL / RDS / AuroraStrong Postgres: schema, indexing, transactionsManaged-DB operations: Multi-AZ, PITR, read replicas, failover, parameter groupsP0
CI/CD (Jenkins, GitLab CI)Pipeline concepts, deployment strategiesWrite a real Jenkinsfile and .gitlab-ci.yml; OIDC to AWS; artefact promotionP0
Kafka / event-drivenOutbox, at-least-once, idempotent consumers — genuinely strongOperational side: MSK, partitions, lag, rebalance, retentionP1
DynamoDBNonePartition-key design, hot partitions, GSI, on-demand vs provisionedP1
MongoDBNone documentedReplica sets, write concern, sharding key basicsP2
Backup / DR / HANone at infra levelRTO vs RPO, the four DR strategies, cross-region, restore drillsP0
ObservabilityStructured logs, metrics awarenessSLI/SLO/error budget, Prometheus, OpenTelemetry, cardinalityP1
Cloud security & complianceJWT, RBAC, AES-GCM at rest, encryption backfillsIAM least privilege, KMS, Secrets Manager, OIDC, SCPs, banking controlsP1
Cost optimisationNoneSavings Plans vs RIs, Graviton, Spot, S3 lifecycle, tagging and showbackP1
Spring BootNoneOperate-not-write: JVM in containers, actuator, heap flags, GC latencyP2
Glue / data architecture / AI-MLNoneGlue crawler + catalog + job model, S3 lake zones, Athena — vocabulary levelP2
TOGAF / SA certificationNoneAWS SAA is the realistic near-term one; know TOGAF ADM by nameP2

21-day prep plan

Weight it towards the P0 rows. You will not become a 15-year AWS architect in three weeks, but you can absolutely become someone who has built the thing once, end to end — and that changes how you answer every question.

DaysFocusConcrete output
1–2AWS fundamentals: IAM, VPC, EC2, S3, RDSA VPC with public/private subnets, NAT, a bastion-less SSM instance
3–5TerraformThe same VPC rebuilt in Terraform, S3 backend with locking, split into modules
6–8Kubernetes and EKSEKS cluster via Terraform; deploy your Go service with probes, HPA, PDB, Ingress
9–10CI/CDA GitLab CI pipeline: test → build → scan → push to ECR → deploy; OIDC, no static keys
11–12Databases: RDS/Aurora HA, PITR, DynamoDBTrigger a failover; do a point-in-time restore; write one DynamoDB access-pattern design
13–14DR, backup, HA designWrite a one-page DR plan with RTO/RPO for a banking service
15–16Observability and SLOsPrometheus + Grafana on the cluster; define 3 SLIs and an error budget policy
17Kafka operationsRevise your outbox story; add partitions, lag, rebalance, retention vocabulary
18Security and costIRSA, Secrets Manager, KMS; a cost-optimisation checklist you can recite
19Go for DevOpsWrite a small client-go tool that lists unhealthy pods across namespaces
20–21Scenarios and behaviouralRehearse the five design scenarios below out loud; polish STAR stories

1. Golang — your differentiator, so lead with it

The JD says Golang is mandatory. On a DevOps pipeline that is unusual, and it is the single reason you are competitive here. Do not answer Go questions like a web developer; answer them like someone who writes the tools that operate the platform.

Why Go is the infrastructure language

  • Single static binary — no runtime, no interpreter, no dependency hell in the image. A FROM scratch image of 8 MB versus a 400 MB Python image.
  • Concurrency that fits operations — polling hundreds of endpoints, draining queues, watching Kubernetes resources, all with goroutines instead of thread pools.
  • The ecosystem is Go — Kubernetes, Docker, containerd, etcd, Terraform, Prometheus, Consul, Vault, ArgoCD. When something misbehaves you can read the source.
  • Cross-compilation — GOOS=linux GOARCH=arm64 go build gives you a Graviton binary from a Mac, which ties straight into the cost conversation.

The graceful-shutdown pattern — expect this exact question

A pod being rolled gets SIGTERM, then SIGKILL after the grace period. A service that ignores SIGTERM drops in-flight requests on every deploy. This is the most common Go-in-Kubernetes question there is.

func main() {
    srv := &http.Server{Addr: ":8080", Handler: router()}

    go func() {
        if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
            log.Fatalf("listen: %v", err)
        }
    }()

    stop := make(chan os.Signal, 1)
    signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
    <-stop
    log.Println("shutdown signal received")

    // Readiness must fail BEFORE we stop accepting connections, so the
    // endpoints controller pulls this pod out of the Service first.
    atomic.StoreInt32(&ready, 0)
    time.Sleep(5 * time.Second) // let kube-proxy/ALB converge

    ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
    defer cancel()
    if err := srv.Shutdown(ctx); err != nil {
        log.Printf("forced shutdown: %v", err)
    }
}

The detail that wins the point: flip readiness to false and sleep before shutting down. Kubernetes removes the pod from Service endpoints asynchronously, so if you shut down immediately you still receive traffic for a second or two and 502s appear on every rollout.

A Go tool that talks to the cluster

Write one of these before the interview so you can say "I wrote a small controller" instead of "I have read about controllers."

// Lists pods that are not Ready across all namespaces — the seed of every
// internal platform CLI.
cfg, err := rest.InClusterConfig()
if err != nil {
    cfg, err = clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
    if err != nil {
        return fmt.Errorf("load kubeconfig: %w", err)
    }
}

clientset, err := kubernetes.NewForConfig(cfg)
if err != nil {
    return fmt.Errorf("build client: %w", err)
}

pods, err := clientset.CoreV1().Pods("").List(ctx, metav1.ListOptions{})
if err != nil {
    return fmt.Errorf("list pods: %w", err)
}

for _, p := range pods.Items {
    for _, c := range p.Status.Conditions {
        if c.Type == corev1.PodReady && c.Status != corev1.ConditionTrue {
            fmt.Printf("%s/%s not ready: %s\n", p.Namespace, p.Name, c.Reason)
        }
    }
}

The next level up, and worth knowing by name: an operator built with controller-runtime, which watches a Custom Resource and drives the cluster towards the declared state through a reconcile loop. The loop must be idempotent and level-triggered — it reads current state and converges, rather than reacting to an event once. That is the same discipline as your Kafka consumers.

The container image

FROM golang:1.23-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# Static binary, no cgo, symbols stripped
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /app ./cmd/api

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /app /app
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/app"]

Talking points: distroless has no shell, so a compromised container has nothing to pivot with; nonroot satisfies a runAsNonRoot admission policy; -trimpath gives reproducible builds; and the final image is single-digit megabytes, which shortens every node pull and every scale-out.

2. AWS — the services this JD actually names

The mental model

Do not memorise the service catalogue. Learn the five they named plus the two that underpin everything (IAM and VPC), and be able to place each in an architecture.

  • IAM — identity and permission. Roles over users, temporary credentials over keys. Long-lived access keys in a pipeline are the finding an auditor opens with.
  • VPC — private subnets for compute and data, public subnets for load balancers only, NAT gateway for egress, security groups as stateful instance firewalls, NACLs as stateless subnet firewalls. VPC endpoints to reach S3 and DynamoDB without traversing NAT, which is both a security and a cost answer.
  • EC2 — instance families (m = general, c = compute, r = memory), Graviton (m7g) for roughly 20% better price-performance on Go workloads, Auto Scaling Groups, AMIs baked with Packer.
  • S3 — eleven nines of durability, storage classes and lifecycle policies, versioning, Object Lock for write-once audit data (a banking favourite), SSE-KMS, and the fact that it is the substrate of the data lake.
  • RDS — managed Postgres/MySQL. Multi-AZ, automated backups, PITR, read replicas, parameter groups, maintenance windows.
  • Lambda — event-driven compute. Know cold starts, provisioned concurrency, concurrency limits, and that Go runs on the provided.al2023 custom runtime now that the go1.x runtime is retired.
  • Glue — serverless Spark ETL plus the Data Catalog. Crawlers infer schema from S3 and populate the catalog; jobs transform between lake zones; job bookmarks stop you reprocessing the same files.

The banking data-platform shape they are hinting at

Source systems (Aurora, Kafka, SFTP drops)
        │
        ▼
   S3  raw zone          ← immutable landing, Object Lock, KMS
        │  Glue crawler → Data Catalog
        ▼
   S3  curated zone      ← Glue Spark job: clean, dedupe, conform, Parquet
        │
        ▼
   S3  consumption zone  ← partitioned by dt, queried by Athena / Redshift
        │
        ├── Athena (analyst SQL)
        ├── QuickSight (dashboards)
        └── SageMaker (fraud / credit models)

If asked about AI/ML in banking, the honest and useful answers are fraud and anomaly detection, credit risk scoring, AML transaction monitoring, customer churn and next-best-action, and document processing for KYC. The engineering point to make is that in a regulated bank the hard part is not the model, it is explainability, model governance, drift monitoring and audit — a model that cannot justify a rejected loan is not deployable.

Well-Architected, as an answering framework

When a design question lands, walk the six pillars out loud. It converts a rambling answer into a structured one and it maps word-for-word onto the JD sentence about performance, security, reliability, availability, observability and compliance.

PillarWhat you say
Operational excellenceIaC for everything, runbooks, automated rollback, game days
SecurityLeast privilege, encryption in transit and at rest, no static keys, private subnets
ReliabilityMulti-AZ, health checks, retries with backoff and jitter, circuit breakers, tested restores
Performance efficiencyRight-sized instances, caching, read replicas, async where latency allows
Cost optimisationSavings Plans, Graviton, Spot for stateless, lifecycle policies, tagging and showback
SustainabilityRight-sizing and Graviton again — mention it once to show you know the sixth exists

3. Terraform — state is the whole interview

Every Terraform interview converges on state. If you can talk about state, locking, drift and blast radius with confidence, you sound experienced even without years of it.

Backend and locking

terraform {
  required_version = "~> 1.9"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.60"
    }
  }

  backend "s3" {
    bucket       = "acme-tfstate-prod"
    key          = "platform/eks/terraform.tfstate"
    region       = "ap-south-1"
    encrypt      = true
    use_lockfile = true   # native S3 locking (Terraform 1.10+)
    # Older estates still use: dynamodb_table = "tf-locks"
  }
}
  • Why remote state: it is shared truth for the team, it is versioned, and it can be encrypted. Local state on a laptop means two engineers can destroy each other's infrastructure.
  • Why locking: two concurrent applies against the same state corrupt it. S3 native locking (or the legacy DynamoDB table) serialises them.
  • State contains secrets — RDS passwords land in state in plaintext. So the bucket is encrypted, versioned, access-logged and locked down. This is a favourite follow-up.
  • Split state by blast radius — networking, cluster, data and application in separate state files, wired together with terraform_remote_state or SSM parameters. One state file for the whole estate means one bad apply can take down everything.

Module structure that a reviewer recognises

infra/
├── modules/
│   ├── network/        # VPC, subnets, NAT, endpoints
│   ├── eks/            # cluster, node groups, IRSA roles
│   ├── rds-aurora/     # cluster, parameter group, backups
│   └── service/        # ECR repo, IAM role, ALB target group
└── live/
    ├── dev/
    │   └── ap-south-1/{ network/, eks/, rds/ }
    ├── uat/
    └── prod/           # same modules, different tfvars — that is the point

The principle: environments differ by variables, not by copied code. If prod and dev drift into different HCL, prod is untested. Version your modules with Git tags so an upgrade is a deliberate, reviewable bump.

The commands and constructs to have ready

  • terraform plan -out=tfplan then terraform apply tfplan — apply exactly what was reviewed, never a re-planned surprise.
  • import blocks (1.5+) — bring existing hand-built resources under management declaratively rather than with the old imperative terraform import.
  • moved blocks — refactor or rename resources without destroy-and-recreate.
  • lifecycle — create_before_destroy for zero-downtime replacement, prevent_destroy on databases, ignore_changes for fields mutated outside Terraform.
  • Drift — someone changed a security group in the console. Detect it with a scheduled plan in CI that alerts on a non-empty diff; fix it by re-applying, and fix the cause by removing console write access in prod.
  • -target — say out loud that it is an emergency tool, not a workflow. Routine targeting means your state is badly split.

Terraform in the pipeline

# .gitlab-ci.yml (fragment)
stages: [validate, plan, apply]

.tf_auth: &tf_auth
  id_tokens:
    AWS_ID_TOKEN: { aud: https://gitlab.com }        # OIDC — no static keys
  before_script:
    - export AWS_ROLE_ARN=$TF_ROLE_ARN
    - echo "$AWS_ID_TOKEN" > /tmp/token
    - export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/token

validate:
  stage: validate
  script: [terraform init -backend=false, terraform validate, terraform fmt -check]

plan:
  stage: plan
  <<: *tf_auth
  script:
    - terraform init
    - terraform plan -out=tfplan -lock-timeout=5m
    - terraform show -no-color tfplan > plan.txt
  artifacts: { paths: [tfplan, plan.txt], expire_in: 1 week }

apply:
  stage: apply
  <<: *tf_auth
  when: manual                # human gate for prod
  only: [main]
  script: [terraform init, terraform apply -auto-approve tfplan]

Three things a senior reviewer looks for here and you should name them unprompted: OIDC federation instead of stored AWS keys, apply consumes the reviewed plan artefact, and a manual gate on production. Add policy-as-code (tfsec, Checkov or OPA) in the validate stage and you have described a governed pipeline, which is exactly the architect half of the JD.

4. Kubernetes, EKS and ECS

ECS versus EKS — have an opinion

ChooseWhen
ECS on FargateSmall-to-mid teams, AWS-only, a handful of services, no platform team to run a cluster. Lower operational surface, deep IAM and ALB integration, no control plane to upgrade.
EKSMany services, portability matters, you need the Kubernetes ecosystem — operators, Argo, service mesh, custom controllers — and you have people to own upgrades.

The honest senior answer: Kubernetes is not free. It buys you a rich ecosystem and costs you a platform team, a quarterly upgrade cadence and a steep failure-mode curve. A bank with a mixed estate usually keeps stable legacy services on ECS and runs the newer, fast-moving platform on EKS — which is precisely why this JD names both.

The deployment manifest, annotated

apiVersion: apps/v1
kind: Deployment
metadata: { name: payments-api }
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate: { maxSurge: 1, maxUnavailable: 0 }   # never dip below capacity
  template:
    spec:
      serviceAccountName: payments-api        # bound to an IAM role via IRSA
      securityContext:
        runAsNonRoot: true
        seccompProfile: { type: RuntimeDefault }
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule    # spread across AZs
          labelSelector: { matchLabels: { app: payments-api } }
      containers:
        - name: api
          image: 1234.dkr.ecr.ap-south-1.amazonaws.com/payments-api:sha-9f2c1ab
          resources:
            requests: { cpu: 200m, memory: 256Mi }
            limits:   { memory: 512Mi }        # memory limit yes, CPU limit deliberately not
          startupProbe:
            httpGet: { path: /healthz, port: 8080 }
            failureThreshold: 30
            periodSeconds: 2
          readinessProbe:
            httpGet: { path: /readyz, port: 8080 }
            periodSeconds: 5
          livenessProbe:
            httpGet: { path: /healthz, port: 8080 }
            periodSeconds: 10
  • Liveness vs readiness vs startup — liveness restarts a wedged process; readiness removes a pod from the Service while it is warming or a dependency is down; startup covers slow boots so liveness does not kill the pod before it ever starts. Never point liveness at a database check — a database blip then restarts every pod in the fleet and turns a degradation into an outage.
  • Image tagged by commit SHA, never latest — immutable, traceable, and rollback is a tag change.
  • maxUnavailable: 0 — the rollout adds a pod before removing one, so capacity never dips.
  • Why no CPU limit — CPU is compressible and a limit causes CFS throttling and tail latency even when the node is idle. Set requests for scheduling, limit memory (which is not compressible and gets you OOMKilled), and leave CPU unlimited. Say this and you sound like someone who has debugged p99 latency.

The EKS-specific things that get asked

  • IRSA — an IAM role assumed by a Kubernetes ServiceAccount through the cluster OIDC provider. It is how a pod reads S3 without node-wide credentials or baked keys. Newer clusters may use EKS Pod Identity, which is simpler to administer; know both names.
  • VPC CNI and IP exhaustion — each pod gets a real VPC IP from the subnet, so undersized subnets stop pod scheduling long before CPU runs out. Mitigate with prefix delegation or larger subnets. This is a classic real-incident question.
  • Autoscaling, two layers — HPA scales pods on CPU or custom metrics (KEDA for queue depth and Kafka lag); Karpenter or Cluster Autoscaler scales nodes. Karpenter is the current answer: it provisions right-sized nodes directly and consolidates underused ones, which is a cost story as well as a scaling one.
  • PodDisruptionBudget — minAvailable: 2 stops a node drain during an upgrade from taking all replicas at once. Voluntary disruptions only; it does not protect against a node dying.
  • Upgrades — EKS minor versions have a support window, so upgrades are a scheduled obligation, not an option. Control plane first, then node groups (blue/green node groups or a rolling replacement), checking deprecated APIs with kubent beforehand.
  • Secrets — base64 is encoding, not encryption. Use the External Secrets Operator or the Secrets Store CSI driver with AWS Secrets Manager, plus envelope encryption of etcd with KMS.
  • Policy — Kyverno or OPA Gatekeeper as admission control to enforce "no root, no latest tag, resources required, images only from our ECR." That is governance made executable, which is a strong architect-track point.

Debugging a CrashLoopBackOff, out loud

kubectl get pods -n payments                # phase, restarts, age
kubectl describe pod <pod> -n payments      # events: image pull? OOMKilled? probe failing?
kubectl logs <pod> -n payments --previous   # the crashed container's logs, not the new one
kubectl get events -n payments --sort-by=.lastTimestamp
kubectl top pod <pod> -n payments           # memory near the limit?

The ordering matters more than the commands: describe before logs, because OOMKilled, ImagePullBackOff and a failing readiness probe are all visible in events and each sends you somewhere completely different. --previous is the flag candidates forget, and it is the only way to see why the container that already died, died.

5. CI/CD — Jenkins, GitLab CI and GitOps

The pipeline shape they want to hear

commit ──▶ lint + unit tests + race detector
        ──▶ SAST + dependency scan (gosec, govulncheck, Trivy)
        ──▶ build image, tag with the commit SHA
        ──▶ image scan; fail on HIGH/CRITICAL
        ──▶ push to ECR (immutable tags enabled)
        ──▶ deploy to dev            (automatic)
        ──▶ integration + contract tests
        ──▶ deploy to UAT            (automatic)
        ──▶ deploy to PROD           (manual approval + change record)
        ──▶ smoke tests, then watch SLOs; auto-rollback on error-budget burn

The two principles to state explicitly: build the artefact once and promote it — the exact image tested in dev is the image that reaches prod, never a rebuild per environment — and every stage is a gate that can fail the pipeline, otherwise it is decoration.

Jenkins, declarative

pipeline {
  agent { kubernetes { yamlFile 'build-pod.yaml' } }   // ephemeral agents on EKS

  environment {
    ECR  = '1234.dkr.ecr.ap-south-1.amazonaws.com/payments-api'
    TAG  = "sha-${GIT_COMMIT.take(7)}"
  }

  stages {
    stage('Test') {
      steps { sh 'go test -race -coverprofile=cover.out ./...' }
    }
    stage('Scan') {
      steps {
        sh 'govulncheck ./...'
        sh 'trivy image --exit-code 1 --severity HIGH,CRITICAL $ECR:$TAG'
      }
    }
    stage('Build & Push') {
      steps {
        sh 'docker build -t $ECR:$TAG .'
        sh 'docker push $ECR:$TAG'
      }
    }
    stage('Deploy PROD') {
      when { branch 'main' }
      steps {
        timeout(time: 30, unit: 'MINUTES') {
          input message: 'Promote to production?', submitter: 'release-managers'
        }
        sh 'kubectl set image deploy/payments-api api=$ECR:$TAG -n payments'
        sh 'kubectl rollout status deploy/payments-api -n payments --timeout=5m'
      }
    }
  }

  post {
    failure { slackSend channel: '#deploys', message: "FAILED ${env.JOB_NAME} ${env.BUILD_NUMBER}" }
  }
}

Jenkins talking points: ephemeral Kubernetes agents rather than long-lived static slaves that accumulate state; shared libraries so fifty repositories are not maintaining fifty copies of the same Groovy; credentials binding so nothing is echoed into a log; and an honest note that Jenkins is the legacy engine in most banks and the migration path is usually GitLab CI or GitHub Actions.

GitOps — the answer that marks you as current

Push-based deploys need cluster credentials in the CI runner, which is the credential you least want to leak. GitOps inverts it: ArgoCD or Flux runs inside the cluster, watches a Git repository of manifests, and reconciles continuously. CI only writes a new image tag to that repository.

  • Git is the source of truth — the cluster state is auditable by git log, which is exactly what a banking change-management process wants.
  • Drift self-heals — a manual kubectl edit in prod is reverted automatically, and you can see that it happened.
  • Rollback is git revert.
  • No cluster credentials in CI — the agent pulls, it is not pushed to.
  • Progressive delivery — Argo Rollouts or Flagger do canary and blue/green with automated analysis: shift 5% of traffic, watch the error rate and latency against a Prometheus query, promote or roll back without a human.

6. Databases — the centre of gravity of this role

"Architect and manage enterprise-level databases with 24/7 availability" and "lead efforts on optimization, backup, and disaster recovery planning" are the two most demanding lines in the JD. Your Postgres knowledge is real; what you must add is the operations layer on top of it.

RDS versus Aurora

RDS PostgreSQLAurora PostgreSQL
StorageEBS volume attached to the instanceDistributed storage layer, 6 copies across 3 AZs, auto-growing
ReplicasUp to 5 read replicas, asynchronous, own storageUp to 15 readers sharing the same storage; replica lag typically milliseconds
FailoverMulti-AZ standby promotion, typically 60–120sTypically under 30s; a reader is promoted
CostCheaper at small scaleMore expensive per hour, better at scale and under heavy read load
DRCross-region read replicaAurora Global Database — RPO around 1s, RTO under a minute

The decision rule to state: Aurora when you need fast failover, many read replicas or cross-region DR with a tight RPO; RDS when the workload is modest and cost dominates. For a bank's system of record with a 24/7 requirement, Aurora with a Global Database is the defensible default.

RTO and RPO — define them before you design anything

  • RPO — how much data you can afford to lose, measured in time. Driven by backup and replication frequency.
  • RTO — how long you can afford to be down. Driven by how fast you can promote or restore.
StrategyRTO / RPOCostFits
Backup and restoreHours / hoursLowestInternal tooling, reporting
Pilot lightTens of minutes / minutesLowImportant but not customer-facing
Warm standbyMinutes / secondsHighCore banking APIs
Multi-site active/activeNear zero / near zeroHighestPayments rails, card authorisation

The sentence that separates a senior answer: "RTO and RPO are business decisions, not engineering ones. I ask the product and risk owners what an hour of downtime and five minutes of lost transactions cost, and the architecture follows from the answer." Then add the uncomfortable follow-up yourself: a backup you have never restored is not a backup. Schedule restore drills, measure the actual restore time, and record it — because in an audit, the evidence of the drill is what is asked for.

PostgreSQL operations to have ready

  • PITR — automated backups plus WAL archiving let you restore to any second inside the retention window. That is your recovery path for a bad migration or a mistaken DELETE, which is a far more common disaster than an AZ failure.
  • Connection pooling — Postgres forks a process per connection, so a few hundred connections hurt. PgBouncer or RDS Proxy in transaction mode; note that transaction-mode pooling breaks session-scoped features like prepared statements and advisory locks, so it is a design choice rather than a free win.
  • Zero-downtime migrations — the banking-relevant version: add a nullable column, backfill in batches, dual-write, switch reads, then drop the old column in a later release. Never a long ALTER holding an ACCESS EXCLUSIVE lock on a hot table. Set lock_timeout and statement_timeout so a migration fails fast instead of queuing every request behind it.
  • Index creation — CREATE INDEX CONCURRENTLY in production; the plain form locks writes for the duration.
  • Vacuum and bloat — MVCC leaves dead tuples; autovacuum reclaims them. Long-running transactions block vacuuming and cause bloat and transaction-ID wraparound risk. Monitor pg_stat_user_tables and the oldest transaction age.
  • Diagnosis — pg_stat_statements for the worst queries by total time, EXPLAIN (ANALYZE, BUFFERS) for the plan, Performance Insights on RDS for wait events.

DynamoDB — think in access patterns, not tables

  • Design backwards from queries. In a relational database you model the data and then query it; in DynamoDB you list every access pattern first and design keys to serve them. Getting this backwards is the single most common mistake and interviewers probe for it.
  • Partition key must spread. A key like status or a date creates a hot partition and throttles. Prefer high-cardinality keys, or add a suffix to shard.
  • GSI vs LSI — a GSI has its own partition key and its own capacity and is eventually consistent; an LSI shares the partition key, must be created with the table, and supports strong consistency.
  • Capacity — on-demand for spiky or unknown traffic, provisioned with auto-scaling for steady, predictable load (meaningfully cheaper at scale).
  • Operational features — PITR, on-demand backups, Streams for change data capture into Lambda, Global Tables for multi-region active/active, DAX for microsecond reads.
  • When not to use it — ad-hoc analytical queries, complex joins, or anything needing multi-entity transactions across arbitrary items. In a bank, ledgers usually stay in Aurora; DynamoDB serves session state, device registries, idempotency keys and high-volume event lookups.

MongoDB, briefly

Replica set of three members with automatic election on primary failure; write with w: "majority" for durability that survives a failover; read preference controls whether you accept stale secondary reads; sharding for horizontal scale, where the shard key choice is as consequential as a DynamoDB partition key. On AWS the choice is between self-managed, Atlas, or DocumentDB (API-compatible, not the same engine).

7. Kafka and event-driven architecture — your existing strength

You already work with the hard parts of this. Present the patterns you know, then extend into the operational vocabulary a platform engineer is expected to have.

What you already have, said in their language

  • Transactional outbox — the event row is written in the same database transaction as the state change, and a relay publishes it. This removes the dual-write problem where the database commits and the broker publish fails, or the reverse.
  • At-least-once delivery, idempotent effects — the broker will redeliver, so the consumer must make reprocessing harmless. A deterministic idempotency key checked before the effect is applied.
  • The event is a trigger, not the authority — consumers re-read the source row rather than trusting a possibly stale payload.
  • Saga compensation — no distributed ACID across services, so a failed step is undone by a compensating action, and ambiguity gets its own state rather than a guess.

The operational layer to add

  • Partitions define parallelism and ordering. Ordering is guaranteed only within a partition, so anything that must be ordered — all events for one account — must share a partition key. Consumers in a group cannot usefully exceed the partition count.
  • Durability settings — acks=all with min.insync.replicas=2 on a replication factor of 3. Anything less and an acknowledged write can be lost on a broker failure, which is not acceptable for money.
  • Idempotent producer and transactions — enable.idempotence=true removes duplicates from producer retries; transactions give you exactly-once between Kafka topics, though not across Kafka and an external database — which is exactly why the outbox exists.
  • Consumer lag is the health metric. Alert on lag trend, not absolute value. Burrow or the MSK/CloudWatch metrics; KEDA can scale consumers on lag directly.
  • Rebalance storms — a slow consumer exceeding max.poll.interval.ms is ejected, triggering a rebalance that slows everyone further. Fix by shrinking batches, moving slow work off the poll loop, or using cooperative sticky assignment.
  • Retention and compaction — time or size retention for event streams; log compaction when the topic is a changelog and only the latest value per key matters.
  • Dead-letter topics — a poison message must not block a partition forever. Retry with backoff a bounded number of times, then route to a DLQ with the failure context, and alert.
  • On AWS — MSK (provisioned or serverless) versus self-managed on EC2. MSK removes broker operations but you still own topic design, quotas and consumer health.

8. Observability and operational stability

The JD names observability explicitly alongside reliability and availability. The framing that lands: monitoring tells you a known thing broke; observability lets you ask a question you did not anticipate.

  • Metrics — numeric time series, cheap, aggregatable, the basis of alerting. Prometheus, or CloudWatch/AMP on AWS. Watch cardinality: a label containing a user ID or a request ID will destroy your metrics store.
  • Logs — structured JSON, correlated by trace ID. In Go that is log/slog. Logs are expensive at scale, so sample the noisy paths and keep the errors.
  • Traces — OpenTelemetry, exported to Jaeger or X-Ray. This is how you find which of eleven services in the request path actually added the 900 ms.

What to measure

  • RED for request-driven services — Rate, Errors, Duration.
  • USE for resources — Utilisation, Saturation, Errors.
  • The four golden signals — latency, traffic, errors, saturation.

SLI, SLO and error budgets

An SLI is the measurement (the proportion of requests served under 300 ms). An SLO is the target (99.9% over 30 days). The error budget is what is left over — 0.1% of 30 days is about 43 minutes of failure you are allowed to spend.

Why this matters to an interviewer: the error budget turns "should we ship?" from an argument into a policy. Budget remaining, ship. Budget exhausted, the next sprint is reliability work. It is how a platform team says no to a release without it being political, and describing it that way is a senior signal.

Alert on symptoms and burn rate, not causes. "Error budget burning at 14x, will exhaust in two hours" is actionable; "CPU is at 85%" wakes someone up for nothing. Every page should have a runbook, and an alert nobody acts on should be deleted.

9. Cloud security and banking compliance

Identity and secrets

  • No long-lived credentials anywhere. Pipelines federate to AWS with OIDC; pods use IRSA or Pod Identity; humans use SSO with short-lived sessions and MFA. If you say only one security sentence in the interview, say this one.
  • Least privilege, enforced structurally — permission boundaries so a team can create roles but not escalate, SCPs at the Organization level so even an account admin cannot disable CloudTrail or launch in an unapproved region (which is how you enforce data residency).
  • Secrets — AWS Secrets Manager with rotation, or Vault. Never in environment variables committed to a repository, never in Terraform variables that land in state unencrypted, never in an image layer.
  • KMS — customer-managed keys for regulated data, with key policies, rotation and an audit trail of every decrypt. Envelope encryption for EKS secrets, RDS, S3 and EBS.

Network and workload

  • Private subnets for all compute and data; only load balancers are public. No SSH — use SSM Session Manager, which gives you an audited session and no open port 22.
  • Security groups referencing other security groups rather than CIDR ranges, so the rules survive re-addressing.
  • WAF in front of public endpoints; Shield for DDoS; rate limiting at the edge.
  • Kubernetes NetworkPolicies for east-west segmentation — default deny, then allow explicitly. Without them, any compromised pod can reach every other pod.
  • Image provenance — scan in CI, block HIGH and CRITICAL, sign with Cosign and verify at admission so only images your pipeline built can run.

The banking layer

  • Data residency — Indian regulation requires payment data to be stored in India; enforce with an SCP restricting regions rather than with a wiki page.
  • Audit trail — CloudTrail organisation-wide to a locked, versioned S3 bucket with Object Lock, so the log of what happened cannot be edited by whoever did it. Application-level admin action logging on top.
  • Segregation of duties — the engineer who writes the change does not approve their own production deploy. This is why the manual gate in the pipeline exists and why GitOps with pull-request review is attractive to auditors.
  • Change management — a production change carries a change record, a rollback plan and a tested backout. Automating the evidence collection rather than fighting the process is the mature position.
  • Standards to name — PCI-DSS for card data, SOX for financial reporting controls, ISO 27001, RBI cyber-security framework, and the general principle of data minimisation.

You are not expected to be a compliance officer. You are expected to know that these constraints exist, to design so they are satisfiable, and to not be surprised when a control blocks a convenient shortcut.

10. Cost optimisation

Explicitly in the JD, and a topic where most engineers have nothing to say — so a prepared answer stands out disproportionately.

  • Right-size first. Most savings come from instances provisioned for a peak that never happens. Compute Optimizer gives you the data; Karpenter consolidation does it continuously on EKS.
  • Commit for the baseline — Compute Savings Plans (flexible across instance family and region) or Reserved Instances for steady load, at roughly 30–50% off. Cover the floor, leave the peak on-demand.
  • Graviton — ARM instances at better price-performance. Go cross-compiles to ARM64 trivially, so for a Go estate this is close to free money. Java is usually fine too; native dependencies are the risk.
  • Spot for anything interruptible — CI runners, batch, Glue, stateless workers behind a queue. Up to 90% off, in exchange for handling a two-minute interruption notice.
  • Storage lifecycle — S3 Intelligent-Tiering or lifecycle rules to Glacier for the raw and archive zones; delete orphaned EBS volumes and old snapshots, which accumulate silently.
  • Network — cross-AZ data transfer is billed and is invisible until you look. Keeping chatty services and their reads zone-aware is a real saving. VPC endpoints for S3 and DynamoDB avoid NAT gateway charges, which are frequently among the top line items.
  • Non-production off out of hours — dev and UAT do not need to run overnight or at weekends; that is roughly a 65% cut on those environments for a scheduled scale-to-zero.
  • Make it visible — a mandatory tagging policy enforced by SCP, then per-team showback dashboards and Cost Anomaly Detection. Cost is a behaviour problem before it is a technology problem; teams that cannot see their spend cannot manage it.

11. Spring Boot — operate it, do not pretend to write it

If asked, be direct: "I am not a Java developer. I can operate Spring Boot services competently, and here is what that involves." That answer is respected; a bluffed one is not.

  • JVM in a container — modern JVMs are cgroup-aware, but you still set -XX:MaxRAMPercentage=75 rather than a fixed -Xmx, so the heap tracks the container limit. Leave headroom for metaspace, thread stacks and direct buffers, or the container is OOMKilled while the heap looks healthy — a genuinely common incident.
  • Health endpoints — Actuator exposes /actuator/health/liveness and /actuator/health/readiness, which map directly onto the two Kubernetes probes. Wire readiness to dependency health and liveness to process health, not the reverse.
  • Slow starts — Spring context initialisation can take tens of seconds, which is what startupProbe is for. Class Data Sharing or a native image with GraalVM if cold start genuinely matters.
  • GC as a latency source — a p99 spike that correlates with nothing in the application is often a garbage-collection pause. G1 by default; ZGC or Shenandoah for low-pause requirements.
  • Connection pools — HikariCP sizing multiplied by replica count is what the database actually sees. Ten pods with a pool of 20 is 200 connections, which will exhaust a default Postgres configuration.

12. The architect half — governance, standards, mentoring

These lines are why the requisition says 15+ years. You cannot manufacture two decades, but you can demonstrate that you think at this altitude, and that is often enough to be taken seriously for the level below.

Architecture Decision Records

The single most credible artefact you can talk about. One short document per significant decision: context, options considered, decision, consequences. Stored in the repository, reviewed like code. It answers the question every organisation eventually asks — "why is it built this way?" — long after the people who decided have left.

# ADR-014: Aurora Global Database for the payments store

## Context
Payments must survive a regional failure with RPO under 5 minutes and
RTO under 15. The current single-region Aurora cluster has neither.

## Options
1. Cross-region Aurora read replica — cheaper, RPO minutes, manual promotion.
2. Aurora Global Database — RPO ~1s, RTO <1min, managed failover, ~35% more cost.
3. Active/active multi-region with conflict resolution — meets everything,
   but the application is not written for write conflicts.

## Decision
Option 2. Option 3 is rejected as an application rewrite we are not funding.

## Consequences
+ Meets the stated RPO/RTO with a documented failover runbook.
- ~35% higher database cost; secondary region capacity sits mostly idle.
- Failover is regional and all-or-nothing; per-service failover is not possible.
- Requires a quarterly failover drill to keep the runbook honest.

Standards and the paved road

Governance that is a document nobody reads fails. Governance that is a golden pathsucceeds: a service template that already has the Dockerfile, the pipeline, the Terraform module, the health endpoints, the dashboards and the alerts wired up. Teams follow the standard because it is the fastest route, not because a committee told them to. Then encode the non-negotiables as automated gates — admission policies, pipeline checks, policy-as-code on Terraform plans — so compliance is verified rather than asserted.

Mentoring, described concretely

Do not say "I mentor juniors." Say what you actually do: code review that explains the reasoning rather than just requesting a change, pairing on the first incident someone takes, writing the runbook together after it, and deliberately handing over a piece of work that is slightly beyond what the person has done before with a safety net underneath. If you have done this at 1Finance, that is your story — tell it in STAR form.

TOGAF in one paragraph

A framework for enterprise architecture built around the ADM — an iterative cycle moving through architecture vision, business architecture, information systems architecture (data then application), technology architecture, opportunities and solutions, migration planning, implementation governance and change management. It also gives you an Architecture Repository and a governance body, usually an Architecture Review Board. You do not need the certification to speak about it; you need to know that it is a process framework for aligning technology to business capability, and that in a bank it exists to make architecture decisions traceable and reviewable.

13. Interview questions and answers

Click a question to expand. Read the answer once, then close it and say it out loud from memory — the second pass is where the preparation actually happens.

Golang

1. Why would a DevOps team write tooling in Go rather than Python or Bash?

Three reasons that matter operationally. Distribution: Go produces a single static binary, so deploying a tool is copying a file — no interpreter version, no virtualenv, no dependency drift on the host. Concurrency: operations work is mostly waiting on network calls, and goroutines with context for cancellation make fan-out with timeouts straightforward compared with thread pools or async frameworks. Ecosystem alignment: Kubernetes, Terraform, Docker and Prometheus are Go, so their client libraries are first-class and when something behaves strangely you can read the source.

I would still use Bash for a ten-line glue script and Python where the team already has Python and the data libraries help. The switch to Go happens when a script becomes a tool that other people depend on — that is the point where types, tests and a single artefact start paying for themselves.

2. Explain goroutines, and how you avoid leaking them.

A goroutine is a function scheduled by the Go runtime rather than the operating system. Stacks start around 2 KB and grow, and the runtime multiplexes many goroutines onto a few OS threads, so hundreds of thousands are practical.

A leak happens when a goroutine blocks forever — on a channel nobody reads, or on a network call with no timeout — and is never garbage collected because it is still runnable in principle. The symptom is memory climbing slowly over days until the pod is OOMKilled.

The disciplines that prevent it:

  • Every goroutine has a way to be told to stop — pass context.Context and select on ctx.Done().
  • Every outbound call has a timeout. No exceptions.
  • The side that writes to a channel closes it; the reader ranges over it.
  • Watch the go_goroutines Prometheus metric. A monotonically rising count is a leak, and pprof at /debug/pprof/goroutine?debug=2 shows you exactly where they are parked.
3. A Go service in Kubernetes gets OOMKilled every few hours. How do you debug it?

Work from cheapest evidence to most expensive.

  1. kubectl describe pod to confirm it is genuinely OOMKilled (exit code 137) rather than a liveness probe restart.
  2. Check whether the limit is simply too low for legitimate usage — compare the memory metric against the limit over a week. Sometimes the fix is a correct limit, not a code change.
  3. If usage grows without plateau, it is a leak. Enable net/http/pprof and capture a heap profile: go tool pprof http://pod:8080/debug/pprof/heap, then compare two profiles taken an hour apart to see what is growing.
  4. The usual culprits: an unbounded cache or map that nothing evicts, goroutines accumulating (check the goroutine profile too), HTTP response bodies never closed so connections and buffers are retained, or slices from large buffers being retained by small sub-slices.
  5. Remember the runtime detail: Go's garbage collector returns memory to the OS lazily, so RSS can look high while the live heap is small. GOMEMLIMIT set slightly below the container limit makes the collector work harder before the kernel kills you, and is the right lever in containers.
4. How do you handle configuration and secrets in a Go service running on EKS?

Configuration comes from the environment, following the twelve-factor principle, so the same image runs in every environment. Non-sensitive values come from a ConfigMap; sensitive values come from AWS Secrets Manager, surfaced into the cluster by the External Secrets Operator or the Secrets Store CSI driver, and mounted or injected as environment variables.

The pod authenticates to AWS through IRSA — its ServiceAccount is annotated with an IAM role, the cluster OIDC provider vouches for it, and the AWS SDK picks up temporary credentials automatically. No access keys in the image, in the manifest or in the repository.

In the application I validate configuration at startup and fail fast if something required is missing, because a service that boots with a broken configuration and fails on the first real request is far harder to diagnose than one that refuses to start.

5. What is a Kubernetes operator, and when would you write one?

An operator is a controller plus a Custom Resource Definition. The CRD extends the Kubernetes API with your own object type, and the controller runs a reconcile loop that reads the desired state from that object, observes actual state, and takes action to close the gap. It encodes the operational knowledge that would otherwise live in a runbook.

The essential property is that reconciliation is level-triggered and idempotent: it looks at the world as it is now and converges, rather than reacting to an event once. That makes it safe to re-run, which is the same reasoning behind idempotent Kafka consumers.

When to write one: when you have a stateful or multi-step operational procedure that is performed repeatedly — provisioning a tenant, managing database users, rotating credentials, orchestrating a complex application's failover. When not to: for something a Helm chart already does. An operator is real software with a real maintenance cost, and most teams that write one did not need it.

AWS and Terraform

6. Walk me through how you would provision a production environment with Terraform.

I would describe structure first, then workflow, then guardrails.

Structure. Reusable modules for network, cluster, data and service, with live configurations per environment that differ only in variables. State split by blast radius — networking, platform and application in separate state files — in an encrypted, versioned S3 bucket with locking enabled. Modules pinned to Git tags so an upgrade is deliberate.

Workflow. Nobody applies from a laptop against production. A merge request runs fmt, validate and a policy scan, then plan, and the plan output is posted to the merge request for review. On merge, the pipeline applies the saved plan artefact so what runs is what was reviewed. Production carries a manual approval from someone who did not write the change.

Guardrails. The pipeline authenticates with OIDC, not stored keys. prevent_destroy on databases and state buckets. A nightly plan that alerts on drift, because drift means someone made a console change and the infrastructure is no longer described by the code. And read-only console access in prod, so drift is rare by construction.

7. Two engineers ran terraform apply at the same time. What happens, and how do you prevent it?

With locking configured, the second apply blocks and then fails with a lock error, which is the correct outcome. Without locking, both read the same state, both write, and the last write wins — leaving state that does not describe reality. You then have orphaned resources Terraform no longer knows about and, worse, resources it thinks exist that do not.

Prevention is state locking: native S3 locking on current Terraform versions, or the DynamoDB lock table on older ones. Recovery, if it has already happened: S3 bucket versioning lets you roll state back to the last good version, then reconcile the difference with terraform plan and targeted import blocks for anything that was orphaned. And the real fix is procedural — humans should not be applying at all, the pipeline should.

8. Someone changed a security group in the console. How do you find out, and what do you do?

Detect three ways: a scheduled terraform plan in CI that alerts on any non-empty diff; AWS Config rules with drift detection; and CloudTrail, which tells you who made the change and when.

Respond by finding out why first. If the change was wrong, re-apply Terraform to revert it. If the change was right — someone fixed a production problem at 2am and the code was incomplete — then the code is what is wrong, and I bring the change into the module so the fix survives the next apply. Blindly reverting an emergency fix is how you cause the second outage.

Prevent by removing write access to production from the console entirely, so the only path to change is the pipeline. That is also what makes the audit story simple: every production change has a merge request, a reviewer and a plan.

9. Design a highly available three-tier architecture on AWS for a banking API.

Walk it top to bottom, naming the availability decision at each layer.

  • Edge — Route 53 with health checks, CloudFront where caching helps, WAF for the OWASP ruleset and rate limiting, Shield for DDoS.
  • Entry — an Application Load Balancer across at least three Availability Zones in public subnets, TLS terminated with ACM certificates.
  • Compute — EKS node groups or ECS Fargate tasks in private subnets, spread across the same three AZs with topology constraints so no single AZ holds a majority of replicas. Horizontal scaling on load, and a PodDisruptionBudget so maintenance cannot drain capacity.
  • Data — Aurora PostgreSQL with a writer and at least one reader in a different AZ, automated backups with PITR, and a Global Database secondary region if the RPO demands it. ElastiCache for the hot read path, also multi-AZ.
  • Async — MSK or SQS between services so a slow downstream produces a queue, not a cascade of timeouts.
  • Cross-cutting — everything in Terraform; secrets in Secrets Manager; least-privilege IAM per workload; CloudTrail and VPC flow logs to a locked bucket; metrics, logs and traces to a single pane; and runbooks for the failure modes.

Then say the part that makes it a senior answer: "multi-AZ is the default and it is cheap; multi-region is expensive and I would only propose it once the business states an RTO that a single region cannot meet." Proposing active/active across regions unprompted signals that you optimise for impressiveness rather than for cost.

10. When would you use Lambda instead of a container on EKS?

Lambda when the work is event-driven, short and spiky: reacting to an S3 upload, processing a DynamoDB stream, a scheduled job, a webhook receiver, glue between services. You pay per invocation and scale to zero, and there is no runtime to patch.

A container when the work is steady, long-running, latency-sensitive or complex: a request-serving API with sustained traffic, anything with a long startup, anything needing persistent connections, and anything where the per-request cost of Lambda at high volume exceeds a reserved instance.

The trade-offs to name: cold starts (mitigated with provisioned concurrency, at which point you are paying for idle capacity and the economics start resembling a container), the 15-minute execution ceiling, the difficulty of connection pooling to a relational database (RDS Proxy exists precisely because of this), and account-level concurrency limits that let one noisy function starve another.

11. How do you reduce a cloud bill that has grown 40% in a quarter?

Measure before cutting. The order I would work in:

  1. Find the delta. Cost Explorer grouped by service and by tag, comparing quarter over quarter. A 40% jump usually has one or two causes, not forty.
  2. Check the usual suspects — an environment left running, a log group with no retention policy, NAT gateway data processing, cross-AZ transfer, snapshots and orphaned EBS volumes accumulating, or a data pipeline reprocessing the whole lake because a job bookmark was disabled.
  3. Right-size with Compute Optimizer and actual utilisation data.
  4. Commit — Savings Plans over the steady baseline once it is right-sized. Committing before right-sizing locks in the waste.
  5. Structural moves — Graviton, Spot for interruptible work, S3 lifecycle policies, scaling non-production to zero out of hours.
  6. Make it stick — mandatory tagging enforced by policy, per-team showback, and Cost Anomaly Detection so the next 40% is caught in a week rather than a quarter.

The framing that lands with an architect: optimise for unit cost — cost per transaction or per customer — not absolute spend. A bill that grows while unit cost falls is a business succeeding.

Kubernetes and containers

12. Explain the difference between liveness, readiness and startup probes, and a way to get them wrong.

Liveness answers "is this process wedged?" — failure restarts the container. Readiness answers "should traffic be sent here right now?" — failure removes the pod from the Service endpoints but leaves it running. Startup answers "has it finished booting?" — it suspends the other probes until it passes, so a slow-starting application is not killed before it is up.

The classic way to get it wrong: pointing liveness at a database connectivity check. The database has a brief blip, every pod fails liveness simultaneously, the whole fleet restarts, the restart storm hammers the recovering database, and a thirty-second degradation becomes a thirty-minute outage. Dependency health belongs in readiness — take yourself out of rotation, stay alive, and come back when the dependency does.

A second one: readiness that only checks the HTTP server is listening. It returns healthy before caches are warm or migrations are done, and the first traffic after a deploy errors.

13. Pods are Pending and never schedule. Walk me through the diagnosis.

kubectl describe pod first — the scheduler writes the reason into events. The reasons and what each means:

  • Insufficient cpu/memory — no node has room for the requests. Either the cluster needs to scale (is Karpenter or the Cluster Autoscaler running, and is it hitting a limit?) or the requests are unrealistically large.
  • Node affinity or taint mismatch — the pod demands a node pool that does not exist, or every node carries a taint the pod does not tolerate.
  • Volume node affinity conflict — an EBS volume is zonal, so a pod bound to a PVC in one AZ cannot schedule in another. Very common in stateful workloads.
  • No IP addresses — on EKS with the VPC CNI each pod takes a real subnet IP, so an exhausted subnet stops scheduling while CPU and memory look fine. Check free IPs in the subnets before you blame anything else.
  • topologySpreadConstraints with DoNotSchedule — the spread rule cannot be satisfied, for example three replicas across two available zones with a maxSkew of 1.
  • Quota — a ResourceQuota on the namespace is already exhausted.
14. How do you do a zero-downtime deployment on Kubernetes?

Zero downtime is the sum of several things, and missing any one of them produces errors that look random.

  • Rolling update with maxUnavailable: 0 so capacity never drops below the replica count.
  • Readiness gating — the rollout only proceeds when new pods report ready, so a broken image stalls instead of replacing everything.
  • Graceful shutdown — the container handles SIGTERM, fails readiness first, waits for the endpoints to converge, then drains in-flight requests before exiting. Set terminationGracePeriodSeconds higher than the drain time.
  • Backward-compatible changes — during a rollout both versions run at once, so the new code must tolerate the old schema and the old code must tolerate the new one. This is why expand-and-contract migrations matter: add the column, deploy code that writes both, backfill, switch reads, then remove the old column in a later release.
  • PodDisruptionBudget so node drains during the same window cannot take the remaining replicas.
  • For higher-risk changes, canary with Argo Rollouts: shift a small percentage, evaluate error rate and latency automatically against a Prometheus query, promote or roll back.
15. What actually happens when you run kubectl apply?

The manifest is sent to the API server, which authenticates the caller, authorises the action through RBAC, runs mutating admission webhooks (sidecar injection, defaulting), validates the object schema, runs validating admission webhooks (your policy engine rejecting a root container here), and persists it to etcd. That is the entire write path, and nothing has run yet.

From there it is controllers watching and reacting. The Deployment controller sees a new Deployment and creates a ReplicaSet; the ReplicaSet controller creates Pods; the scheduler sees unbound Pods and assigns each to a node by filtering then scoring; the kubelet on that node sees a Pod assigned to it, pulls the image through the container runtime, sets up the network via CNI and mounts volumes via CSI, then starts the container and begins reporting status. kube-proxy or the CNI programs the routing so the Service sends traffic to the pod once readiness passes.

The idea worth stating explicitly: nothing is imperative. You declared a desired state and independent control loops converged towards it. That is why the system self-heals, and why a controller must be safe to re-run.

16. Your cluster costs have doubled but traffic is flat. Where do you look?
  • Over-requested resources. Requests drive scheduling, so pods asking for 2 CPU and using 100m force nodes to be added for capacity nobody consumes. Compare requests against actual usage across the fleet — this is usually the answer, and a Vertical Pod Autoscaler in recommendation mode gives you the numbers.
  • Node fragmentation — many partly-empty nodes. Karpenter consolidation bin-packs and terminates the remainder.
  • Instance choice — on-demand where Spot would do for stateless workloads, x86 where Graviton would do.
  • Forgotten workloads — abandoned namespaces, preview environments that never got cleaned up, CronJobs whose completed pods accumulate.
  • Outside compute — the load balancer per Ingress instead of one shared, cross-AZ traffic between chatty services, log volume to CloudWatch with no retention policy, unattached EBS volumes from deleted StatefulSets.
17. How do you secure a Kubernetes cluster?

Layer by layer, because there is no single control that does it.

  • Identity — cluster access through SSO mapped to RBAC roles, namespaced and least-privilege. No shared kubeconfig with cluster-admin.
  • Workload identity — IRSA or Pod Identity so each workload gets exactly the AWS permissions it needs, and no node-wide credentials.
  • Admission control — Pod Security Admission at restricted level, plus Kyverno or Gatekeeper policies: no privileged containers, no host network or host path mounts, run as non-root, resources required, images only from our registry.
  • Network — default-deny NetworkPolicies with explicit allows, private API endpoint, nodes in private subnets.
  • Supply chain — scan images in CI and block on HIGH/CRITICAL, sign with Cosign and verify at admission, use minimal base images so there is less to be vulnerable.
  • Secrets — external secret store, etcd encrypted with KMS, never a plain Secret checked into Git (or if GitOps, then sealed or encrypted with SOPS).
  • Runtime and audit — audit logging on, Falco or GuardDuty for EKS runtime threat detection, and regular patching of the control plane and nodes.

Databases, HA and disaster recovery

18. Design a backup and disaster recovery plan for a core banking database.

Start with the numbers, not the technology. I ask the business what RPO and RTO they require and what the cost of downtime is, because those two numbers determine everything and they are not an engineering choice.

Assuming a core banking system — say RPO of one minute and RTO of fifteen:

  • In-region resilience — Aurora PostgreSQL, writer plus readers across Availability Zones, automatic failover in under 30 seconds. This covers the common failure, which is an instance or an AZ, not a region.
  • Point-in-time recovery — continuous backup with WAL, retention set to the regulatory minimum or longer. This is the real protection against the most likely disaster: a bad deployment or an erroneous bulk update, which replication faithfully copies to every replica.
  • Cross-region — Aurora Global Database for roughly one-second RPO and sub-minute promotion, meeting the stated RTO with room to spare.
  • Immutable copies — periodic snapshots exported to an S3 bucket in a separate account with Object Lock, so ransomware or a compromised admin cannot delete the backups. In banking this is usually a hard requirement, not a nicety.
  • Application-side — the services must reconnect on failover rather than holding a dead connection, retries must be idempotent, and the DNS/endpoint change has to propagate. A database that fails over in 30 seconds behind an application that needs a restart has an RTO measured in whatever the restart takes.

Then the part most candidates omit: the drill. A quarterly exercise that actually promotes the secondary and runs the application against it, timed and documented. Until you have restored, you have a backup strategy on paper and an unknown in practice — and the drill is also the evidence an auditor asks for.

19. What is the difference between an RDS read replica and a Multi-AZ deployment?

They solve different problems and candidates routinely confuse them. Multi-AZ is for availability: a synchronous standby in another AZ that you cannot read from, promoted automatically when the primary fails. A read replica is for scale: an asynchronous copy you can read from, which does not fail over automatically and can lag.

The consequences follow from synchronous versus asynchronous. Multi-AZ costs write latency but loses no committed data on failover. A read replica costs nothing on the write path but can be behind, so reading your own write immediately after committing may return stale data — which is why you route reads that must be consistent to the writer.

You generally want both: Multi-AZ for resilience, replicas for read scale. Note also the newer RDS Multi-AZ DB cluster option, which gives two readable standbys and faster failover, sitting between classic Multi-AZ and Aurora.

20. A query that was fast last month now takes eight seconds. How do you approach it?
  1. Confirm the scope — one query or everything? If everything, it is a resource or lock problem, not a query problem. Check CPU, IOPS, connection count and Performance Insights wait events first.
  2. Get the plan — EXPLAIN (ANALYZE, BUFFERS). Compare estimated against actual rows: a large divergence means the planner has bad statistics, and the fix may simply be ANALYZE.
  3. Look for the usual regressions — a sequential scan where an index used to be chosen because the table grew past a threshold; an index that is no longer selective; a plan flip after data distribution changed; bloat from dead tuples making scans read far more pages than the row count suggests.
  4. Check for blocking — pg_stat_activity and pg_locks for a long-running transaction holding a lock, which also blocks autovacuum and compounds the bloat.
  5. Then fix at the right level — an index (created concurrently), a rewritten query, a covering index for an index-only scan, or a design change if the access pattern is fundamentally wrong. And check pg_stat_statements to see whether this query is even the one consuming the most total time, because the slowest query and the most expensive query are frequently not the same.
21. How would you choose between Aurora, DynamoDB and MongoDB for a new banking service?

By the shape of the data and the access patterns, not by preference.

  • Aurora PostgreSQL for anything with relational integrity, multi-row transactions, or ad-hoc querying — accounts, ledgers, customers, anything a regulator will ask you to reconcile. Strong consistency and real transactions are not optional for money.
  • DynamoDB where the access patterns are known, simple and enormous: session state, idempotency keys, device registries, rate-limit counters, event lookups by key. Single-digit-millisecond reads at any scale, but you must design the keys around the queries and you give up ad-hoc querying.
  • MongoDB where documents genuinely vary in shape and you want flexible querying over them — a product catalogue, aggregated customer profiles, content. Less compelling if the schema is actually stable, in which case Postgres with a JSONB column often gives you the flexibility without a second database to operate.

And the architect's caveat worth saying: every additional datastore is a permanent operational tax — backups, DR, monitoring, patching, expertise, on-call. Polyglot persistence is correct when the workload genuinely demands it and expensive theatre when it does not.

22. How do you run a schema migration on a table with 200 million rows, with no downtime?

Expand and contract, in separate deployments.

  1. Expand — add the new column as nullable with no default that rewrites the table. On modern Postgres a nullable add is metadata-only and instant; a volatile default rewrites the whole table and must be avoided.
  2. Dual-write — deploy code that writes both old and new, reads old. Both versions of the application are running during a rollout, so this step has to be compatible in both directions.
  3. Backfill in batches — a few thousand rows per transaction, with a pause between batches, monitoring replication lag. One giant UPDATE holds locks, bloats the table and can push replicas minutes behind.
  4. Verify — count and sample-compare old against new before trusting it.
  5. Switch reads — deploy code that reads new, still writes both. This is the rollback point: if the new column is wrong, revert the deploy and the old column is still authoritative.
  6. Contract — a later release stops writing the old column and eventually drops it, once you are confident no rollback will need it.

Throughout: lock_timeout and statement_timeout set, so a migration that cannot get its lock fails immediately instead of queuing every subsequent query behind it and taking the service down. Indexes created with CONCURRENTLY. And the whole thing rehearsed against a restored copy of production first.

23. What does 24/7 availability actually require, beyond a Multi-AZ database?

It requires that every routine operation be doable without downtime, which is a much broader claim than a resilient database. Concretely:

  • Schema migrations are expand-and-contract, never a maintenance window.
  • Deployments are rolling or canary, and both versions can coexist.
  • Database patching uses the managed maintenance window with Multi-AZ so the standby is patched and promoted — and the application survives the failover without a restart.
  • Certificate rotation, credential rotation and dependency upgrades are automated and tested, because expiry is a leading cause of self-inflicted outages.
  • Capacity is headroom, not exactly enough. N+1 at minimum, so losing an AZ does not mean losing the service.
  • There is an on-call rotation with runbooks, and the alerts that page are the ones a human can act on.
  • The failure modes have been rehearsed — game days, failover drills, restore drills — because an untested recovery path is a hypothesis.

And the honest framing: 24/7 is not a technical setting, it is a budget. Each additional nine multiplies cost and constrains how fast the organisation can change things. Part of the architect's job is making that trade-off explicit rather than promising five nines and funding three.

Pipelines, events and security

24. Design a CI/CD pipeline for a cloud-native application in a bank.

The engineering part is standard; the banking part is the controls, and mentioning those is what distinguishes the answer.

  • Build once, promote the artefact. The image tested in dev is byte-identical to the one in production, tagged by commit SHA, with immutable tags enabled in ECR so a tag cannot be repointed.
  • Quality gates that can fail the build — unit tests with the race detector, SAST, dependency vulnerability scanning, image scanning, and infrastructure policy checks on the Terraform plan.
  • No standing credentials — the runner federates to AWS via OIDC and receives a short-lived role.
  • Environment promotion — dev automatic, UAT automatic with integration tests, production behind a manual approval by someone other than the author. That is segregation of duties, and it is a control an auditor will specifically ask about.
  • Deployment via GitOps — CI writes the new tag to a manifest repository, ArgoCD reconciles. Git history is the change record, which makes the audit trail a by-product rather than extra work.
  • Progressive rollout with automated rollback — canary with analysis on error rate and latency; a failed analysis rolls back without a human decision at 3am.
  • Evidence — every deploy links commit, approver, test results, scan results and the change ticket. In a regulated environment, being able to produce that automatically is worth more than pipeline speed.
25. How do you guarantee a payment is never processed twice in an event-driven system?

You do not get exactly-once delivery, so you build at-least-once delivery with idempotent effects. The broker may redeliver; the effect must be applied once.

The mechanism, concretely:

  • Every message carries a deterministic idempotency key derived from the business event, not a random ID generated at publish time — otherwise a republish produces a new key and defeats the whole thing.
  • The consumer writes that key to a uniquely-indexed table inside the same database transaction as the effect. A duplicate violates the unique constraint, the transaction rolls back, and the message is acknowledged as already handled.
  • The check happens before any business validation such as a balance check, so a retry after a successful apply does not fail on insufficient funds and get misread as a real failure.
  • The publish side uses the transactional outbox: the event row is written in the same transaction as the state change, and a relay publishes it afterwards. This eliminates the dual-write failure where the database commits and the broker does not.
  • The event is a trigger, not the authority — the consumer re-reads the source record rather than acting on a payload that may be stale by the time it is processed.
  • Where a third party is involved and its response is ambiguous — a timeout with no answer — the record moves to an explicit pending reconciliation state rather than guessing. Guessing on money is how you create a double debit or a silent loss.

This is your genuine experience from the HR community platform ledger. Keep the ownership framing honest — you worked on that system rather than designing it — and present the patterns as ones you understand deeply and would apply.

26. Consumer lag on a Kafka topic is growing. What do you do?
  1. Confirm the direction — is production up, or consumption down? A traffic spike and a stalled consumer look identical on a lag graph and have opposite fixes.
  2. If consumption slowed — check consumer logs for errors and rebalances. Repeated rebalances mean a consumer is exceeding max.poll.interval.ms, usually because processing got slower; the fix is smaller poll batches or moving the slow work off the poll loop.
  3. Check downstream — consumers are usually slow because something they call is slow: a database under load, a third-party API, a lock. The lag is a symptom.
  4. Scale, if partitions allow — consumers in a group cannot exceed the partition count, so if you are already at parity you must add partitions. Note the cost: adding partitions changes key-to-partition mapping and breaks ordering guarantees for existing keys, so it is not a casual change.
  5. Check for a poison message — one message failing and retrying forever blocks its partition entirely. That needs a bounded retry and a dead-letter topic.
  6. Longer term — alert on lag trend and on estimated time-to-drain rather than a raw number, and autoscale consumers on lag with KEDA.
27. How do you handle secrets across environments without ever storing one in Git?
  • Source of truth — AWS Secrets Manager (or Vault), one path per environment, with rotation enabled where the downstream supports it. RDS credentials rotate natively.
  • Into the cluster — the External Secrets Operator or the Secrets Store CSI driver syncs them into the pod. The manifest in Git references a secret name; it never contains a value.
  • Into the pipeline — OIDC federation so the runner assumes a role and fetches what it needs at run time. No secret is stored in the CI system at all.
  • Terraform — remember that resource attributes land in state in plaintext, so state is encrypted, versioned and tightly access-controlled. Better still, have Terraform create the secret with a generated value and never see it, or reference an out-of-band secret by ARN.
  • If GitOps forces a value into a repository — SOPS or Sealed Secrets, so what is committed is ciphertext only decryptable inside the cluster.
  • Detection — a pre-commit hook and a CI scanner (gitleaks or trufflehog) because the control that matters most is catching the mistake, and any secret that ever reached a repository is considered compromised and must be rotated, not just deleted.
28. Production is down. Walk me through your first fifteen minutes.

Restore service first, find the cause second. Those are separate activities and conflating them extends outages.

  1. Declare and assign. Someone is incident commander, someone communicates to stakeholders, someone investigates. Without roles, five people debug the same thing and nobody updates anyone.
  2. Establish blast radius — what is broken, for whom, since when. The dashboard answers this if the SLIs are right.
  3. Ask what changed. The overwhelming majority of incidents follow a change: a deploy, a config flip, a migration, a certificate expiring, a feature flag, a traffic shift. Check the deploy timeline against the start of the graph.
  4. Mitigate with the fastest lever — roll back the deploy, revert the flag, fail over, scale up, shed load. Rolling back a suspected change is almost always faster than diagnosing it, and you can investigate the artefact afterwards.
  5. Confirm recovery against the same signals that showed the failure, not by assertion.
  6. Afterwards — a blameless postmortem with a timeline, contributing factors and concrete action items with owners and dates. Blameless because the goal is a system that tolerates the mistake, and the moment people fear the review, information stops flowing and you lose the ability to learn at all.

14. Design scenarios — rehearse these out loud

Architect-track interviews are won in the scenario round. Use the same opening every time: clarify requirements, state assumptions, sketch the happy path, then attack your own design with failure modes. Interviewers reward candidates who find the holes themselves.

Scenario A — Migrate a monolith to microservices on AWS

Clarify: why are we doing this? If the answer is not a concrete pain — deploy coupling, scaling one component, team autonomy — the correct recommendation may be to modularise the monolith and not split it at all. Say that.

Approach: strangler fig. Put a gateway in front, carve out one bounded context at a time — start with something low-risk and high-value, usually a read-heavy or genuinely independent capability — and route that path to the new service while everything else continues to hit the monolith. Never a big-bang rewrite.

Data is the hard part: a shared database defeats the purpose, so each service needs to own its data eventually. Bridge with change data capture or an outbox during the transition, and accept a period of dual-write with reconciliation.

Attack it yourself: distributed transactions become sagas; a single query becomes N network calls with N failure modes; debugging needs distributed tracing from day one; and organisational readiness matters more than the technology, because microservices owned by one team are just a distributed monolith with worse latency.

Scenario B — The nightly Glue job now overruns into business hours

Clarify: what is the actual deadline, how much data, and has volume grown or has the job changed?

Diagnose: Spark UI for skew — one task taking far longer than the rest means the partition key is unbalanced. Check whether job bookmarks are enabled (a disabled bookmark reprocesses the entire history every night, which is a very common cause of exactly this symptom). Check file sizes: millions of small files in S3 is a listing and task-overhead problem, not a compute problem.

Fix: compact small files, partition the lake by date so queries and jobs prune, convert to Parquet with appropriate column ordering, repartition to address skew, and scale DPUs only after the shape problems are fixed — scaling a skewed job mostly buys idle executors.

Then structurally: move from nightly batch to incremental processing, or to streaming if the business actually needs freshness. Add a job-duration SLO with alerting so the trend is visible before it becomes an incident.

Scenario C — Design the deployment platform for forty teams

The real question is governance at scale, not technology. Forty teams doing forty things is the failure mode.

Answer with a paved road: a service template that ships with the Dockerfile, pipeline, Terraform module, health endpoints, dashboards and alerts already wired. Teams get to production in a day by following it, which is why they follow it.

Encode the non-negotiables as automated gates — admission policies, pipeline checks, policy-as-code on Terraform plans — so standards are verified rather than asserted in a wiki.

Multi-tenancy: namespace per team with quotas, RBAC and NetworkPolicies; separate accounts for production versus non-production; tagging enforced so cost is attributable.

Leave an exit: a documented exception process with an architecture review, because a platform with no escape hatch gets routed around, and shadow infrastructure is worse than a sanctioned exception.

Scenario D — An entire Availability Zone goes dark at 10am

What should happen automatically: the load balancer health checks fail and stop routing there; Kubernetes reschedules the lost pods onto surviving nodes; Aurora promotes a reader in another AZ in under a minute; the autoscaler adds capacity in the remaining zones.

What actually goes wrong, and is the interesting half of the answer: capacity was sized for exactly three zones so losing one means running at 66% and browning out — you need N+1; pods were not spread with topology constraints so one zone held most replicas; stateful pods are bound to zonal EBS volumes and cannot reschedule; connection pools hold dead connections because the application never reconnects after failover; and the remaining zones get a thundering herd of retries that takes them down too, unless retries have backoff, jitter and a circuit breaker.

Afterwards: a postmortem, and a game day that deliberately removes a zone in non-production so the next one is rehearsed rather than discovered.

Scenario E — Regulator requires all customer data to stay in India

Enforce structurally, not procedurally. A Service Control Policy at the AWS Organization level denying every region except ap-south-1 (plus the global services that have no regional form) means no engineer in any account can create a resource elsewhere, even with admin rights.

Then prove it: AWS Config rules and Security Hub for continuous compliance evidence; CloudTrail to a locked, Object-Locked bucket so the audit log cannot be altered; tagging that marks data classification so scanning can find what moved.

Then handle the awkward parts honestly: DR within a single country means multiple AZs and possibly a second Indian region rather than a global secondary; some managed services are not available in every region and that constrains the architecture; third-party SaaS and monitoring vendors may process data abroad, which is a contract and data-flow question, not just an infrastructure one; and backups and logs are customer data too, which is the part teams most often miss.

15. Behavioural and STAR stories

At this level the behavioural round is testing judgment and scope, not enthusiasm. Prepare five stories, each in Situation, Task, Action, Result form, with a real number in the result. Draw them from what you have actually done.

PromptStory to useThe point to land
Tell me about a difficult technical decisionA design choice on the Go platform where you weighed two approachesYou considered options and consequences, not just the one you liked
A time you improved reliability or performanceA query or endpoint you optimised — with the before and after latencyYou measured first, then changed; you did not guess
A production incident you handledAny real failure you debugged, with the timelineMitigate first, diagnose second, then fix the class of problem
A time you disagreed with a senior personA review or design discussion where you pushed backYou disagreed with evidence and committed once the decision was made
Mentoring or raising the barReviews, pairing, the encryption backfill pattern you spread across modulesYour impact extended past your own commits
Something you shipped safely that could have broken thingsThe encryption backfill, or a migration on a live tableIdempotency, staged rollout, verification, a rollback path

For the "biggest weakness" question, this JD hands you an honest and strong answer: "Depth of hands-on cloud operations. I have strong software and data fundamentals and I have been closing the infrastructure gap deliberately — here is what I built and what I learned from it." Naming the real gap and showing the work against it is far more convincing than a rehearsed weakness that is secretly a strength.

16. Questions to ask them

These also let you find out which of the two jobs in this JD is the real one, which you need to know before an offer.

  • This requisition reads as both a hands-on DevOps role and an enterprise architecture role. Which is the day-to-day, and is there a separate person doing the other half?
  • Where is the Golang in the estate today — platform tooling, product services, or both? How much Go would I be writing in a typical month?
  • What is the split between EKS and ECS, and is there a direction of travel?
  • What is the current state of Terraform — is everything in code, or is there a legacy footprint that was click-built?
  • What are the stated RTO and RPO for the tier-one services, and when was the last failover drill?
  • Is there an on-call rotation, what does the page volume look like, and who owns production for these services?
  • How are architecture decisions made and recorded — is there an ARB, are there ADRs?
  • What does success in this role look like at six months?
  • Is this a Virtusa-badged role on a specific banking client, and how long is the engagement?

17. Certifications, in priority order

  1. AWS Certified Solutions Architect – Associate — explicitly named in the JD, broadest return, and it forces you to learn the service catalogue properly. Four to six weeks of evening study is realistic. Start here.
  2. HashiCorp Terraform Associate — small, cheap, and directly relevant to a named requirement. Two weeks.
  3. CKA (Certified Kubernetes Administrator) — hands-on and practical, and the one that most changes how you actually answer cluster questions. Six to eight weeks.
  4. AWS Solutions Architect – Professional — only after the Associate and real experience; it is a genuinely hard exam and premature attempts waste months.
  5. TOGAF 9/10 Foundation — worth it if you are targeting the architect track long-term and the account values it. Low priority against the others for a hands-on seat.

A certification never beats a built thing. If you have three weekends, a working Terraform-provisioned EKS cluster running your own Go service with a pipeline behind it will do more for this interview than a badge, because it gives you specifics to answer with.

18. Traps to avoid

  • Do not claim AWS or Terraform production years you do not have. The follow-up questions are specific — which backend, which failure, what did the plan show — and a bluff collapses in ninety seconds and taints everything true you said before it.
  • Do not say "I have used Kubernetes" if you mean Docker Compose. Say "I have run containerised services in production and I have been learning Kubernetes hands-on; here is the cluster I built."
  • Do not over-engineer the design answers. Proposing multi-region active/active for a service with no stated RTO signals poor judgment, not ambition. Ask for the requirement first.
  • Do not skip the requirements-clarification step in a scenario question. Jumping straight to a diagram is the most common way senior candidates lose the design round.
  • Do not present the HR community platform architecture as yours. You contributed to it. "The design is X and here is why I think that is right" is a strong, honest framing that still demonstrates the understanding.
  • Do not let the Golang round go by in five minutes. It is the reason you are in this pipeline. If they do not go deep, steer there: offer the graceful-shutdown problem or the client-go tool unprompted.
  • Do not be vague about the experience gap. Name it early, once, with what you are doing about it — then spend the rest of the hour on what you can actually do.

The one thing to remember

You are not competing with fifteen-year DevOps architects on their ground. You are the candidate who writes production Go, thinks correctly about idempotency and failure, and is building the cloud depth deliberately and visibly.

That is a real and uncommon profile. Lead with it, be honest about the rest, and let the interviewer decide which seat you fit — because the seat you actually fit is one you can hold.