{"id":1152,"date":"2026-07-23T14:05:00","date_gmt":"2026-07-23T08:35:00","guid":{"rendered":"https:\/\/lastroundai.com\/blog\/?post_type=iq&#038;p=1152"},"modified":"2026-07-21T22:32:44","modified_gmt":"2026-07-21T17:02:44","slug":"ci-cd","status":"publish","type":"iq","link":"https:\/\/lastroundai.com\/interview-questions\/ci-cd","title":{"rendered":"CI\/CD Interview Questions (2026): Pipelines, Must-Know Q&#038;A"},"content":{"rendered":"<p>A senior SRE candidate at a fintech startup gave a clean, textbook answer on blue-green deployments in March 2026, then lost the offer two questions later. The interviewer asked what happens to in-flight database connections during the traffic switch. He hadn&#8217;t thought about it, because most tutorials stop at &#8220;traffic moves from blue to green&#8221; and never mention that the old environment can&#8217;t just vanish the instant someone flips the router.<\/p>\n<p>Here&#8217;s an opinion that might be wrong: I think the CI\/CD section of a DevOps or platform engineering interview has quietly gotten harder than the Kubernetes section, not because the concepts are more advanced, but because there&#8217;s no cheat sheet for &#8220;what actually breaks during a live cutover.&#8221; Kubernetes trivia is memorizable in a weekend. A pipeline&#8217;s failure modes usually aren&#8217;t, not until you&#8217;ve watched one fail at an inconvenient hour.<\/p>\n<p>This page covers CI\/CD interview questions across pipeline design, build artifacts, testing, deployment strategy, rollback, secrets, environment promotion, GitOps, and the DORA metrics teams use to check whether any of it is actually working. It&#8217;s written tool-agnostic where the concept is tool-agnostic, and calls out Jenkins, GitHub Actions, or GitLab CI by name only where the answer genuinely differs between them.<\/p>\n<div class=\"iq-stats not-prose\"><div class=\"iq-stat\"><span class=\"iq-stat__value\">52<\/span><span class=\"iq-stat__label\">Questions<\/span><\/div><div class=\"iq-stat\"><span class=\"iq-stat__value\">Build once, promote everywhere<\/span><span class=\"iq-stat__label\">Core Concept<\/span><\/div><div class=\"iq-stat\"><span class=\"iq-stat__value\">3<\/span><span class=\"iq-stat__label\">Deploy Strategies<\/span><\/div><div class=\"iq-stat\"><span class=\"iq-stat__value\">Under 1 hour<\/span><span class=\"iq-stat__label\">DORA Elite Recovery<\/span><\/div><\/div>\n<h2>CI vs. CD: the difference interviewers actually check for<\/h2>\n<p>This is the warm-up, and it&#8217;s a worse warm-up than it looks. Confusing &#8220;delivery&#8221; and &#8220;deployment&#8221; out loud in the first two minutes sets a bad tone for the rest of the loop.<\/p>\n<div class=\"iq-dsec iq-dsec--easy\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"easy\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Easy questions<\/h2><span class=\"iq-dsec__n\">15<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the real difference between continuous integration, continuous delivery, and continuous deployment?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">CI\/CD<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Continuous integration means merging code frequently, with an automated build and test run on every push, so integration problems surface in minutes instead of at the end of a sprint. Continuous delivery means the codebase stays in a deployable state at all times, but a human still decides when it actually ships. Continuous deployment removes that human gate entirely: anything that clears the pipeline goes to production automatically, no button, no ticket, no approval step.<\/p>\n<p>Interviewers use this as an early filter. Calling CI &#8220;when you use GitHub&#8221; or treating delivery and deployment as interchangeable is the single most common miss here, and it tells them you&#8217;ve used the tools without understanding what practice each one actually names.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Walk through the stages of a typical CI\/CD pipeline for a containerized service.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pipeline Design<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Lint and format check, then unit tests, then build a single artifact (a container image, tagged by commit SHA rather than something mutable) and push it to a registry. From there, deploy that exact artifact to a lower environment, run integration and smoke tests against it, pass a gate (manual approval or an automated policy check), deploy the same artifact to production, then run a short post-deploy verification watching error rate and latency before calling the whole thing done.<\/p>\n<p>The detail interviewers actually listen for is &#8220;the same artifact.&#8221; A pipeline that rebuilds the image separately for staging and production breaks the one guarantee testing gave you, and that gap is where a good number of &#8220;it worked in staging&#8221; incidents come from.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Where does a smoke test sit in a pipeline, and how is it different from a full regression suite?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Testing<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A smoke test runs right after a deploy, against the real (or near-real) environment, checking a small set of critical paths, can a user log in, does the health endpoint respond, can a checkout complete, in under a minute or two. It answers one question: did the deploy fundamentally work. A regression suite is the much larger set of unit and integration tests run earlier, before merge or build, and it answers a different question entirely: is the code still correct.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What actually makes a deployment rollback-safe, versus just having a rollback command that technically exists?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Rollback<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Rollback-safe means the previous version can run correctly against whatever state the system is in right now, not just that a command exists to redeploy old code. A rollback that redeploys old code against a database schema it was never written to understand isn&#8217;t safe. It just fails differently, and sometimes more quietly.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why is committing a .env file with real API keys to a private repo still a bad idea, even if nobody outside the company can see it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Secrets<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Private doesn&#8217;t mean access-controlled at the right level. Contractors, a wide CI service account, or a misconfigured internal fork can all end up with read access to that repo. Git history keeps the secret forever too, even after someone deletes the file in a later commit, so the actual fix is rotating the leaked key through a secrets manager, not just removing it from the tree and hoping nobody checked out an older commit.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What does &#039;pipeline as code&#039; mean, and why do most teams prefer a Jenkinsfile or .gitlab-ci.yml over clicking through a UI to configure a build?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pipeline as Code<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Pipeline as code means the build and deploy steps are defined in a text file that lives in the same repo as the application, version controlled right alongside the code it builds. A Jenkinsfile, .gitlab-ci.yml, or .github\/workflows\/*.yml are all the same idea: instead of an admin clicking buttons in a web UI to wire up jobs, the pipeline definition is just another file that gets reviewed in a pull request.<\/p>\n<p>The practical win is history and reproducibility. If someone breaks a stage, git blame tells you who changed it and when, and you can revert with a normal git revert instead of hunting through a UI trying to remember what a checkbox used to say. It also means every branch can carry its own version of the pipeline, so testing a change to the CI process itself is just a normal PR, no separate change process for infrastructure. The downside is that pipeline files can get gnarly, deeply nested YAML with anchors and includes, so teams that lean on this heavily usually extract shared logic into reusable workflows or included templates rather than copy-pasting the same 200 lines into every repo.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why does continuous integration work better with trunk-based development than with long-lived feature branches?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Branching Strategy<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>CI is fundamentally about integrating changes frequently and catching conflicts early. If everyone merges small changes into main multiple times a day behind feature flags, the integration problem stays small, each merge only has to reconcile with whatever landed in the last few hours. That&#8217;s trunk-based development.<\/p>\n<p>Long-lived feature branches invert that. A branch that lives for three weeks accumulates drift from main, and when it finally merges you get a giant diff, painful conflict resolution, and often a wave of test failures that have nothing to do with the feature itself, just incompatible assumptions that built up in isolation. The big merge defeats the purpose of CI, because you weren&#8217;t continuously integrating, you were continuously diverging and then doing one enormous integration at the end. Feature flags are what make trunk-based development survivable, you merge incomplete work behind a flag that&#8217;s off in production, so main stays releasable at any point without every feature being finished.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What problem does a merge queue (or merge train) solve that plain &#039;require CI to pass before merge&#039; doesn&#039;t?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Merge Queue<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Requiring CI to pass before merge only guarantees a PR&#8217;s branch passed tests against the state of main at the time CI ran. If two PRs both pass individually and merge close together, the resulting main after both merges was never actually tested as a combination. That&#8217;s a semantic conflict, two changes that don&#8217;t touch the same lines but break each other logically, like one PR renaming a function and another PR adding a new caller of the old name.<\/p>\n<p>A merge queue fixes this by serializing merges: it takes ready PRs, applies them one at a time or in batches on top of current main, runs CI against that combined state, and only then updates main. If a PR in the middle of the queue fails, it gets kicked out and the rest re-tests without it. This costs more CI minutes because you&#8217;re re-running tests for combinations, not just individual branches, but for a busy repo with a dozen people merging a day, it&#8217;s the difference between a green main that&#8217;s actually green and a main that looks green until the next person pulls it.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What is a build cache in CI, and what actually goes wrong if you don&#039;t have one?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Build Caching<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A build cache stores the outputs of expensive, repeatable steps, installed dependencies, compiled objects, downloaded base images, keyed off something like a lockfile hash, so the next run can restore them instead of redoing the work. npm ci reinstalling node_modules from scratch, or Maven pulling every jar from a repository, can easily be the slowest part of a pipeline, often slower than the actual test run.<\/p>\n<p>Without caching, every pipeline run pays that cost in full, stretching feedback time and, at scale, racking up real compute cost since you&#8217;re paying for CPU time spent downloading the same packages repeatedly. The catch is cache correctness. The key needs to actually reflect anything that changes the output, usually a hash of the lockfile plus the OS and architecture. Key it too loosely, say just on branch name, and you&#8217;ll restore a stale cache with outdated dependencies and get bizarre failures that don&#8217;t reproduce locally. Key it too tightly and you lose most of the benefit because every commit invalidates it.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between SAST and DAST, and where does each one sit in a CI\/CD pipeline?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Security Testing<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>SAST, static application security testing, scans your source code without running it, looking for patterns like SQL string concatenation instead of parameterized queries, hardcoded secrets, or known-vulnerable dependency versions. Tools like Semgrep, CodeQL, or Snyk Code do this, and they run early, usually right alongside unit tests on every pull request, because they&#8217;re fast and don&#8217;t need a deployed environment.<\/p>\n<p>DAST, dynamic application security testing, actually attacks a running instance of the application, throwing malformed requests at it, probing for injection points, checking response headers, the kind of thing a tool like OWASP ZAP does against a staging deployment. Because it needs something live to hit, DAST runs later, typically after deploy to staging, and it&#8217;s slower and noisier than SAST. SAST finds bad patterns in code that was never executed, DAST finds runtime behavior that only shows up once the app is actually serving requests, like a misconfigured CORS header or an endpoint that leaks a stack trace on error.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s a preview environment, and why do teams spin one up per pull request instead of just using a shared staging server?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Preview Environments<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A preview environment is a full, isolated deployment of the application built from a specific pull request&#8217;s branch, usually torn down automatically when the PR closes or merges. Vercel and Netlify popularized this for frontend apps, but it works just as well for backend services with ephemeral namespaces in Kubernetes.<\/p>\n<p>The problem with a single shared staging server is that it becomes a bottleneck. If three PRs are in flight, whoever deploys last overwrites whoever deployed first, and reviewers end up testing the wrong version or fighting over who gets staging next. A preview environment per PR means a reviewer can click a link in the PR and see exactly that change running in isolation, with its own database or a seeded copy, without stepping on anyone else. The tradeoff is cost and complexity, spinning up a full environment per PR, especially one with a database, message queue, and dependent services, isn&#8217;t free, so teams often scope preview environments to just the frontend or a subset of services, with shared infrastructure for anything too expensive to duplicate.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the test pyramid, and why does a healthy CI pipeline run far more unit tests than end-to-end tests?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Test Pyramid<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The test pyramid is a shape: a large base of fast, isolated unit tests, a smaller layer of integration tests that check how a few components work together, and a thin top layer of end-to-end tests that drive the whole system through a real, or close to real, environment. The proportions matter more than any specific test type.<\/p>\n<p>Unit tests are cheap, milliseconds each, no network, no database, so you can run thousands on every commit and still get results in under a minute. End-to-end tests are the opposite, they need a deployed environment, real network calls, sometimes a browser driving a UI, and they&#8217;re an order of magnitude slower and flakier because there are so many more moving parts that can fail for reasons unrelated to the thing you&#8217;re actually testing, a slow database connection, a timing issue in the UI. A pipeline that inverts the pyramid, lots of E2E tests and few unit tests, ends up slow and flaky, and engineers start ignoring failures because half of them are false alarms. The pyramid shape keeps the fast, reliable tests doing most of the work and reserves the expensive tests for the handful of critical user flows that really need full-system coverage.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How do feature flags decouple deployment from release, and why does that distinction matter for CI\/CD?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Feature Flags<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Deployment is getting new code running in production. Release is making a feature visible or usable to users. Without feature flags those two things are the same event, merging and deploying code means users see it immediately. Feature flags split them apart. Code for a half-finished feature can sit behind a flag that&#8217;s off, get deployed to production dozens of times as it&#8217;s built incrementally, and only get released when someone flips the flag on, independent of any deploy.<\/p>\n<p>This matters for CI\/CD because it removes the pressure to hold back a deploy until a feature is complete. Teams can merge to main and deploy continuously without every commit needing to be a finished, user-ready feature. It also gives you a release mechanism that doesn&#8217;t need a deploy at all, if a newly released feature causes problems, you flip the flag off, which is instant and doesn&#8217;t require rolling back the binary. The tradeoff is that flags accumulate debt if nobody removes them after a feature is fully rolled out, so mature setups have a process, and sometimes tooling, for flagging stale flags and forcing cleanup.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the tradeoff between self-hosted CI runners and a vendor&#039;s hosted runners like GitHub-hosted or GitLab SaaS runners?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">CI Runners<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Hosted runners are the default for a reason: no infrastructure to maintain, they scale automatically, and you&#8217;re billed per minute of usage. For most projects that&#8217;s the right call, especially early on when build volume is low and nobody wants to spend engineering time babysitting build machines.<\/p>\n<p>Self-hosted runners become worth it once you hit specific pain points: hosted runner minutes get expensive at scale, a busy monorepo can burn thousands of dollars a month, you need hardware the vendor doesn&#8217;t offer, a specific GPU, an ARM chip matching production, more RAM than the hosted tier gives you, or you need runners inside a private network to reach internal services without exposing them to the internet. The cost of self-hosting isn&#8217;t just the machines, it&#8217;s patching them, handling runner registration and scaling, usually with an autoscaler like actions-runner-controller for Kubernetes, and making sure a compromised job can&#8217;t persist state onto the runner and affect the next job that lands on it, a real security concern with non-ephemeral self-hosted runners that hosted, throwaway VMs don&#8217;t have.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s an artifact registry, and why does a pipeline push a build there instead of just copying files to the deployment target?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Artifact Registry<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>An artifact registry, a Docker registry, an npm registry, Artifactory, Nexus, is a versioned, addressable store for build outputs. Every build gets pushed there with an identifier, a Docker image digest, a semver-tagged npm package, and it stays there, immutable, until something explicitly deletes it. Deployment then means pulling a specific, already-built artifact by its identifier, not building fresh or copying a file that might silently differ from what was tested.<\/p>\n<p>Copying files directly to servers loses that traceability, there&#8217;s no record of exactly what&#8217;s running where, no way to guarantee the file on a server is bit-for-bit the same as what CI produced, and no easy way to roll back to a prior version because the old file might already be overwritten. A registry also gives you content-addressable references. A Docker image referenced by its sha256 digest can&#8217;t drift the way a mutable tag can, which is the whole reason deploying an exact digest is safer than deploying whatever a floating tag resolves to right now. The registry is also the natural point to plug in vulnerability scanning and retention policies, since everything that ever got built passes through it.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-dsec iq-dsec--medium\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"medium\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Medium questions<\/h2><span class=\"iq-dsec__n\">25<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">A team says they do continuous deployment, but a release manager still has to approve every production push in a ticketing tool. What are they actually doing?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">CI\/CD<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Continuous delivery, not deployment. A manual approval step, however lightweight, is a human gate, and continuous deployment is specifically defined by the absence of one. There&#8217;s nothing wrong with running delivery instead of deployment. Plenty of regulated industries choose it on purpose.<\/p>\n<p>What matters in an interview is naming the gap correctly instead of repeating the label the team happens to use internally. I&#8217;ve sat through more than one hiring conversation where &#8220;we do continuous deployment&#8221; turned out to mean a Slack message and a thumbs-up emoji from someone&#8217;s manager, which is still a human gate wearing a casual outfit.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why is tagging a Docker image &#039;latest&#039; considered risky in a CI\/CD pipeline?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Build Artifacts<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>&#8216;latest&#8217; is mutable. It doesn&#8217;t tell you what code is actually running, and it turns rollback into guesswork, since you can&#8217;t pin a redeploy to whatever version was previously live. Tag with something immutable instead, the commit SHA, or a semantic version paired with the SHA, so every artifact in the registry maps to exactly one build.<\/p>\n<p>The rollback angle bites hardest in practice. A `kubectl rollout undo` command needs distinguishable image tags to roll back to. If every deploy pushed &#8216;latest,&#8217; a rollback just redeploys whatever &#8216;latest&#8217; currently points to, which is the same broken build you&#8217;re trying to escape.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">A service has twelve other teams depending on its API. Where do contract tests belong in the pipeline, and what do they catch that integration tests don&#039;t?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Testing<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Contract tests run in CI before merge, verifying that the responses your service returns still match what each consumer actually expects, often using a tool like Pact that checks the provider&#8217;s build against contracts the consumers published. That catches a breaking schema change before it ships, something a normal integration test usually misses, because the team that broke the contract is testing against its own assumptions, not a consumer&#8217;s.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Blue-green, canary, and rolling deployments, what&#039;s the actual difference, and when would you pick each?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Deployment Strategy<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Rolling deployments replace old pods with new ones gradually and are the Kubernetes default, cheap on infrastructure, but rollback isn&#8217;t instant since old and new versions briefly serve traffic side by side. Blue-green keeps two complete environments and flips all traffic at once, near-instant rollback, at the cost of running double the infrastructure while both are live. Canary sends the new version to a small slice of traffic first, watches metrics, then ramps up gradually if nothing looks wrong.<\/p>\n<p>Pick blue-green when instant rollback matters more than infrastructure cost, payment processing is the usual example. Pick canary when you have solid metrics and want statistical confidence before a full rollout. Rolling is fine for everyday, low-risk changes where a few minutes of mixed versions won&#8217;t hurt anyone.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why does blue-green give you near-instant rollback while a rolling deployment doesn&#039;t?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Deployment Strategy<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Blue-green rollback is a single switch: the router flips back to an environment that&#8217;s still fully running, unchanged, in the background. Rolling deployments have already torn down some fraction of the old pods to make room for new ones by the time something goes wrong, so &#8220;rolling back&#8221; means rolling the old version back in gradually, another full replacement cycle, not a flip.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How fast should a rollback actually be? Is &#039;as fast as possible&#039; a real target?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Rollback<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>There&#8217;s no single universal number, it depends on architecture, but DORA&#8217;s own research gives elite performers something to compare against: teams in that tier recover from a failed deployment in under an hour (<a href=\"https:\/\/dora.dev\/research\/2024\/dora-report\/\" target=\"_blank\" rel=\"noopener noreferrer\">DORA, 2024 State of DevOps Report<\/a>). &#8220;As fast as possible&#8221; isn&#8217;t quite the right target either. I think whether the team has actually rehearsed a rollback recently matters more than the raw speed number. A fast rollback nobody has tested is still a gamble the first time it gets used for real.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How does a running container actually get a secret without it living in the image or showing up in pipeline logs?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Secrets<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Never bake it into the image, image layers are inspectable and often cached in a registry other people can pull. Inject it at runtime instead: mounted as a file from a secrets manager like Vault or AWS Secrets Manager through an init container or a CSI driver, or handed to the container as an environment variable pulled just-in-time by the orchestrator at start, never passed as a build argument or written into a values file the pipeline echoes to its own logs.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s environment promotion, and what&#039;s actually supposed to change as a build moves from dev to staging to production, the artifact or the config?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Environment Promotion<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Environment promotion means moving one validated build through increasingly trusted stages, dev, then staging, then production, gaining confidence at each gate. The artifact itself, the compiled binary or container image, should stay byte-for-byte identical the whole way through. Only the configuration around it changes: database URLs, feature flags, replica counts, secrets, all injected at deploy time. If the artifact changes between environments, the guarantee testing gave you is already broken before it ever reaches production.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">bash<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-bash\">\n\n#!\/usr\/bin\/env bash\n\n# promote.sh: deploy an already-built, already-tested image\n\n# with environment-specific config only\n\nENV=$1\n\nIMAGE_TAG=$2\nexport DATABASE_URL=$(vault kv get -field=url secret\/$ENV\/database)\n\nexport FEATURE_FLAG_NEW_CHECKOUT=$(vault kv get -field=enabled secret\/$ENV\/flags)\nkubectl set image deploy\/app app=registry.example.com\/app:$IMAGE_TAG -n $ENV\n\nkubectl set env deploy\/app DATABASE_URL=$DATABASE_URL -n $ENV\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What is GitOps, and how is it actually different from a CI\/CD pipeline that pushes changes with kubectl apply?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">GitOps<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>GitOps, per the CNCF&#8217;s own working group, rests on four principles: the desired state is expressed declaratively, stored with versioning and immutability, pulled automatically by an agent rather than pushed from outside, and continuously reconciled against whatever is actually running (<a href=\"https:\/\/opengitops.dev\/\" target=\"_blank\" rel=\"noopener noreferrer\">OpenGitOps Principles<\/a>). A normal CI pipeline pushes changes outward and holds the cluster&#8217;s credentials in the pipeline itself. GitOps flips that around: an in-cluster agent like Argo CD or Flux pulls from git and reconciles, so cluster credentials never leave the cluster, and git becomes the one source of truth you can diff or revert.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s configuration drift, and how does a GitOps agent actually catch it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">GitOps<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Drift happens when someone, or something, changes a live resource directly, a manual kubectl edit during an incident, a hotfix nobody wrote back to git, so the running state stops matching what&#8217;s declared in the repo. A pull-based GitOps agent continuously diffs actual cluster state against the git-declared state and either alerts on the mismatch or reverts it automatically, depending on the configured sync policy. A one-off CI push never checks again after the fact. That&#8217;s the actual gap GitOps closes.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Jenkins, GitHub Actions, or GitLab CI, how do you actually choose for a new project in 2026?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Tooling<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>JetBrains&#8217; State of Developer Ecosystem survey, published in October 2025, put organizational adoption at 33 percent for GitHub Actions, 28 percent for Jenkins, and 19 percent for GitLab CI, with plenty of overlap since most shops run more than one tool (<a href=\"https:\/\/blog.jetbrains.com\/teamcity\/2025\/10\/the-state-of-cicd\/\" target=\"_blank\" rel=\"noopener noreferrer\">JetBrains, State of CI\/CD 2025<\/a>). Eighteen percent of respondents reported using no CI\/CD tool at all, a strange number this late into the practice being mainstream.<\/p>\n<p>Pick GitHub Actions if your code already lives on GitHub and you want tight pull request integration with minimal ops overhead. Pick Jenkins if you need arbitrary plugins or legacy on-prem integration and someone is willing to babysit the plugin ecosystem, its 28 percent share despite being the oldest tool here says something about how sticky old infrastructure investments actually are. Pick GitLab CI if you&#8217;re already on GitLab and want CI, a container registry, and deploy tooling in one platform instead of stitching three products together.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What are the four DORA metrics, and which one correlates most with overall org performance?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">DORA Metrics<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Deployment frequency and lead time for changes measure throughput. Change failure rate and time to restore service (recovery time after a failed deploy) measure stability. DORA&#8217;s 2024 report puts elite performers on-demand for deployment frequency, with sub-day lead time, roughly a 5 percent change failure rate, and recovery in under an hour (<a href=\"https:\/\/dora.dev\/research\/2024\/dora-report\/\" target=\"_blank\" rel=\"noopener noreferrer\">DORA, 2024 State of DevOps Report<\/a>).<\/p>\n<p>My take, and plenty of people will push back on it: deployment frequency is the metric recruiters like to brag about, &#8220;we deploy 40 times a day,&#8221; and the one I trust least on its own. Forty deploys a day at a 25 percent change failure rate is worse than two deploys a day at 3 percent, and a bare frequency number hides that completely.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What goes wrong when a CI cache key is too loose, and how does that show up as a bug?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Cache Invalidation<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>If the cache key doesn&#8217;t fully capture everything that determines the cache&#8217;s contents, you get a stale cache restored on top of a build that expected fresh dependencies. The classic version is caching node_modules keyed only on branch name instead of a hash of package-lock.json. Someone bumps a dependency version in the lockfile, CI restores the old cached node_modules because the branch name didn&#8217;t change, and the build runs against the wrong dependency version. Tests pass locally, where node_modules was actually reinstalled, but fail, or worse silently pass with wrong behavior, in CI.<\/p>\n<p>The fix is keying the cache off a hash of the actual input, the lockfile content, layered with a fallback restore key so a partial cache hit still saves time without risking correctness. A subtler version of this bug shows up with Docker layer caching. If a Dockerfile copies source code before installing dependencies, a cache hit on the dependency-install layer can mean it never re-runs even when a dependency version changed, because Docker&#8217;s cache invalidation is based on the layer&#8217;s inputs at that point in the file, not the final state. Ordering COPY package.json before COPY . matters specifically so the dependency layer&#8217;s cache key only depends on the manifest, and does get invalidated when the manifest actually changes.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s a matrix build, and what&#039;s the tradeoff of testing across a large matrix versus a small one?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Matrix Builds<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A matrix build runs the same job multiple times with different combinations of variables, say Node 18, 20, and 22 crossed with Ubuntu, macOS, and Windows, producing nine parallel jobs instead of one. It&#8217;s how you get confidence that a library works across the actual combinations your users run, rather than just the one environment the maintainer happens to develop on.<\/p>\n<p>The tradeoff is straightforward multiplication. A 3&#215;3 matrix is 9x the CI minutes and 9x the places something can fail for environment-specific reasons that have nothing to do with the actual code change, a Windows path separator bug, a macOS-specific missing dependency. Wide matrices also multiply flakiness, since any one cell being flaky makes the whole matrix look red intermittently, and debugging which cell actually failed and why takes real time. The practical approach most teams land on is running a full matrix on a scheduled nightly build or before a release, but only the single most representative combination, latest Node on Linux, on every PR, so day-to-day feedback stays fast and the full matrix catches cross-platform regressions before they ship, not on every commit.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How do you deal with a flaky test in CI without either ignoring real bugs or letting it block every merge?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Flaky Tests<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The wrong instinct is to just re-run until it passes and move on, because that trains the team to treat red as noise, and eventually a real failure gets lost in the pattern of just rerunning it. The other wrong instinct is deleting the test, because sometimes flakiness is the test surfacing a genuine race condition or timing bug in the application, not a bad test.<\/p>\n<p>The practical approach is quarantine with a deadline. When a test is confirmed flaky, fails intermittently with no code change, it gets tagged and moved out of the required, blocking test suite into a separate non-blocking job that still runs and reports but doesn&#8217;t fail the build. That buys time to investigate without blocking every unrelated PR on someone else&#8217;s flaky test, but it needs an owner and a ticket, because quarantined tests that never get fixed just become permanent dead weight that quietly stops testing anything. Common root causes worth checking before quarantining: shared mutable state between tests that run in parallel, a hardcoded sleep instead of waiting on an actual condition, or a test asserting on wall-clock time in an environment where CI runners can be slow and jittery under load.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s an SBOM, and why are pipelines increasingly required to generate one on every build?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">SBOM Generation<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A software bill of materials is a machine-readable manifest listing every component, direct and transitive, that went into a build, every library, its exact version, and often its license and origin. Tools like Syft or cdxgen generate one automatically as a pipeline step, usually output in SPDX or CycloneDX format, and it gets attached to the build artifact.<\/p>\n<p>The driver is supply chain incidents like Log4Shell, where the hard part wasn&#8217;t fixing the vulnerable library, it was figuring out which of hundreds of services actually had log4j-core somewhere in their dependency tree, sometimes three levels deep through a transitive dependency nobody remembered adding. An SBOM turns that into a query instead of a fire drill, you can grep every SBOM in your artifact registry for the affected package and version instantly. It&#8217;s also increasingly a compliance requirement. The US executive order on cybersecurity pushed federal software vendors toward mandatory SBOMs, and that requirement flows downstream into any vendor selling to the government or to companies under similar regulatory pressure.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between a readiness probe and a liveness probe, and what happens if you mix them up?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Health Probes<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A liveness probe answers whether this process is stuck and needs to be killed and restarted. If it fails repeatedly, the orchestrator kills the container and starts a fresh one, on the assumption that a restart fixes whatever&#8217;s wrong, a deadlock, a memory leak that&#8217;s degraded the process past recovery. A readiness probe answers a different question, should this instance currently receive traffic. A pod can be alive and healthy but not ready, for example while it&#8217;s still warming up a cache or waiting on a database connection pool to establish, and during that window it should be pulled out of the load balancer&#8217;s rotation without being killed.<\/p>\n<p>Mixing them up causes real incidents. If you wire your liveness probe to check downstream dependencies, say can I reach the database, a transient database blip causes every instance to fail liveness simultaneously, get killed, and restart, potentially all at once, turning a 30-second database hiccup into a full outage as the whole fleet cycles. The liveness check should only ever ask if the process itself is responsive, nothing about dependencies. The readiness check is the right place to ask about dependencies, because taking a pod out of rotation while it can&#8217;t serve a request is safe and reversible, it just needs to check things it can&#8217;t handle traffic without.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s connection draining, and why does a rolling deployment need it to avoid dropping in-flight requests?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Connection Draining<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>When an orchestrator terminates an old instance during a rolling deploy, it sends a termination signal, SIGTERM in Kubernetes, and then, after a grace period, a hard kill, SIGKILL, if the process hasn&#8217;t exited. Connection draining is the practice of, on receiving that signal, stopping acceptance of new connections while letting requests already in flight finish normally, instead of dying immediately and cutting off whoever was mid-request.<\/p>\n<p>Without it, a rolling deploy that replaces instances one at a time will still intermittently drop requests, the load balancer might route a request to an instance a split second before it&#8217;s terminated, or the instance might be mid-response when the kill signal arrives. The fix has two parts working together: the load balancer needs to deregister the instance from its target pool and stop sending it new traffic, and the application needs to catch the termination signal, finish existing requests with a bounded timeout, and only then exit. Kubernetes&#8217;s terminationGracePeriodSeconds controls how long the app gets before the hard kill, and it needs to be set longer than your slowest realistic request, or you&#8217;ll cut off exactly the long-tail requests during every single deploy.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the expand-contract pattern for database migrations, and why does it matter when app code and schema deploy independently?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">DB Migrations<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The core problem is that during a rolling deployment, old and new versions of the application run simultaneously against the same database for some window of time, seconds to minutes depending on rollout speed. If a migration renames a column or drops one the old code still reads, the old instances start erroring the moment the migration runs, well before the deploy finishes.<\/p>\n<p>Expand-contract splits any breaking schema change into safe, backward-compatible steps spread across multiple deploys. Expand: add the new column alongside the old one, deploy application code that writes to both, so both old and new code paths work against the current schema. Migrate: backfill existing data into the new column, and once you&#8217;re confident every write path is populating it, switch reads to the new column in a later deploy. Contract: only after the old column has been unused for a full deploy cycle, and you&#8217;ve confirmed nothing external still depends on it, do you actually drop it, in yet another separate deploy. It&#8217;s slower than doing a rename in one migration, but every deploy in the sequence is safe against both the version running before it and after it, which is the actual requirement once you can&#8217;t guarantee an instant, atomic cutover.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why does a deploy pipeline need concurrency control, and what actually breaks if two deploys to the same environment run at once?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Deploy Locking<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>If two people trigger a deploy to production within a few minutes of each other and the pipeline lets both run concurrently, you can end up with a genuinely undefined final state. Two rolling deployments interleaving means some instances get replaced with version A, some with version B, and depending on which one finishes last, the deployment that wins isn&#8217;t necessarily the one that was supposed to. Worse, if both trigger the same database migration or infrastructure change, a Terraform apply say, you can get a race on the same resource, partial applies, or corrupted state that&#8217;s genuinely hard to reason your way back from.<\/p>\n<p>The fix is a deploy lock, usually implemented as a concurrency group in the CI tool itself, GitHub Actions has concurrency with a group name and cancel-in-progress, GitLab has resource_group, so a second deploy to the same environment either queues behind the first or cancels it outright rather than running in parallel. The subtlety is scope. Lock too broadly, one lock for all environments, and a staging deploy blocks an unrelated production deploy for no reason. Lock too narrowly, per-service instead of per-environment, and two services that share a migration or a piece of shared infrastructure can still race even though neither pipeline individually looks unsafe.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">When is a deployment freeze window actually justified, and what&#039;s the risk of leaning on it too much?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Freeze Windows<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A freeze window is a defined period where deploys to production are paused, code-frozen, typically around a major known-risk event, Black Friday for e-commerce, a big product launch, a known high-traffic period where the team wants zero unrelated risk stacked on top of the risk that&#8217;s already expected. The justification is real, during peak load on-call has less slack to absorb a bad deploy, and the cost of an incident is higher, more users affected, more revenue at stake, so the marginal value of shipping one more change that week is outweighed by the downside if it goes wrong.<\/p>\n<p>The risk is treating freeze windows as a crutch instead of an exception. If a team has quarterly freezes that last two weeks each, engineers start batching up changes to land right before the freeze starts, which recreates the big-risky-deploy problem continuous deployment is supposed to solve, just compressed into the days before freeze. A freeze is only healthy when it&#8217;s genuinely rare and short, paired with a real emergency-change process for anything that actually can&#8217;t wait, a security patch doesn&#8217;t get to skip the freeze policy because it&#8217;s inconvenient, and the team is honest that a freeze is a temporary risk-reduction tool, not a substitute for actually having a deployment process trustworthy enough to run during a busy period.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why would you pin a third-party GitHub Action to a commit SHA instead of a version tag like @v4?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Action Pinning<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A tag like @v4 is mutable. Whoever owns that action&#8217;s repository can force-push a new commit to the v4 tag at any time, and every workflow referencing @v4 will pull that new code on its very next run, with zero review on your end. If that maintainer&#8217;s account gets compromised, or a malicious actor gets a PR merged and then re-tags v4 to point at it, every pipeline pinned to @v4 executes attacker-controlled code with whatever permissions and secrets that job has access to. The tj-actions\/changed-files compromise in 2025 worked exactly this way, injecting a secrets-dumping payload by retagging a widely used action.<\/p>\n<p>Pinning to a full commit SHA fixes the reference to an exact, immutable snapshot of code, since SHAs can&#8217;t be reassigned to different content. It&#8217;s more maintenance, you have to manually bump the SHA, or use a bot like Renovate that does it via PR so the change gets reviewed, instead of getting automatic updates, but that friction is the point. Any change to what code actually runs goes through your normal review process instead of happening silently on someone else&#8217;s push. Dependabot and Renovate both support pinning-with-update-PRs as their default recommendation for third-party actions specifically because of this class of attack.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the tradeoff between letting Dependabot or Renovate auto-merge dependency updates versus reviewing every bump manually?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Dependency Updates<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Manual review of every dependency bump doesn&#8217;t scale. A moderately sized service can easily have 200 plus transitive dependencies, and patch-level bumps happen constantly, most of them genuinely inconsequential, a typo fix in a changelog, an internal refactor with no API change. Requiring a human to review and approve every single one means either dependency PRs pile up unreviewed for weeks, which is worse than auto-merging because you&#8217;re now behind on actual security patches, or someone rubber-stamps them without really reading the diff, which gives you the illusion of review without the substance.<\/p>\n<p>The practical middle ground most teams land on is auto-merging patch and minor version bumps automatically, gated on the full CI suite passing, since semver in theory guarantees those are backward compatible, in practice plenty of libraries violate semver, which is the real risk here. Major version bumps, and anything flagged with a known CVE, get routed to a human, because those are exactly the changes likely to have breaking API changes or require your own code changes to adopt the fix. The failure mode to watch for is auto-merge on a service where CI doesn&#8217;t have real coverage. If your test suite is thin, auto-merging on green CI is auto-merging on a false signal, and you&#8217;ll find out about the breakage in production instead.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What does a &#039;require status checks to pass before merging&#039; branch protection rule actually enforce, and where does it commonly get bypassed by accident?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Branch Protection<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The rule blocks the merge button, and the API, from allowing a PR into the protected branch until the named CI checks report success against the current head of that PR. It&#8217;s the actual mechanism that turns require tests to pass from a policy people are supposed to follow into something the platform enforces regardless of intent, nobody can merge a red PR by mistake or under deadline pressure.<\/p>\n<p>The common bypass isn&#8217;t malicious, it&#8217;s structural. Admins and repo owners frequently have a separate permission to merge even with failing or pending checks unless include administrators is explicitly turned on, which a lot of teams don&#8217;t realize until someone with admin access merges around a failing check during an incident and it becomes habit. Another gap: the rule protects the merge into the branch, but if your deploy pipeline triggers off a separate event, a tag push, a manual dispatch, rather than off the protected branch itself, someone can still deploy code that never went through a protected merge at all. And status checks named in the rule have to match the actual job names exactly. Rename a CI job and the branch protection rule silently stops enforcing anything for that check until someone notices and updates the required-checks list.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why do multi-stage Docker builds matter for CI\/CD image size and security, and what&#039;s a concrete pattern for a compiled language?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Docker Builds<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A single-stage Dockerfile for a compiled app typically needs the full build toolchain, compilers, headers, sometimes a package manager with dev dependencies, just to produce the binary, and if you ship that same image to production, all of that tooling ships with it. That&#8217;s a bigger attack surface, anything installed is something an attacker who gets a foothold can potentially use, and a bigger image, meaning slower pulls and slower rollouts.<\/p>\n<p>A multi-stage build splits this into a build stage with the full toolchain that compiles the binary, and a final stage that starts from a minimal base image and only copies the compiled output across.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">dockerfile<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-dockerfile\">\n\nFROM golang:1.22 AS builder\n\nWORKDIR \/src\n\nCOPY go.mod go.sum .\/\n\nRUN go mod download\n\nCOPY . .\n\nRUN CGO_ENABLED=0 go build -o \/app .\/cmd\/server\nFROM gcr.io\/distroless\/static-debian12\n\nCOPY \u2013from=builder \/app \/app\n\nENTRYPOINT [\u201d\/app\u201d]\n<\/code><\/pre><\/div><\/p>\n<p>The final image has no shell, no package manager, no Go toolchain, just the static binary and whatever the distroless base needs to run it. That shrinks the image from potentially a gigabyte down to tens of megabytes, and it means a container escape or RCE in the running app doesn&#8217;t hand an attacker a full Linux userland with curl, bash, and a package manager to pivot with. The tradeoff is debuggability, you can&#8217;t kubectl exec into a distroless container and poke around with a shell, so teams that adopt this usually keep a debug variant of the image around, or lean on ephemeral debug containers for troubleshooting instead.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-dsec iq-dsec--hard\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"hard\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Hard questions<\/h2><span class=\"iq-dsec__n\">12<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">You inherit a pipeline where every merge to main auto-deploys straight to production, no staging environment at all. Is that continuous deployment done right, or a red flag?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">CI\/CD<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Technically it&#8217;s continuous deployment. Whether it&#8217;s a good idea depends entirely on what&#8217;s backing it up. Skipping a staging environment is a bigger risk multiplier than the missing environment itself, unless the team has built real safety nets: feature flags to decouple deploy from release, fast automated rollback, and a canary step that catches a bad build on a small slice of real traffic before everyone sees it.<\/p>\n<p>My honest take, and some engineers will push back on this: skipping staging isn&#8217;t wrong on principle. Some of the best-run pipelines I&#8217;ve read post-mortems about do exactly this. It only works if the team built the safety net instead of skipping it and calling speed a feature on its own.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Your team rebuilds the container image separately for staging and for production, same Dockerfile, same source, but a fresh build each time. What&#039;s the actual risk, and how would you fix it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Build Artifacts<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The risk is a non-reproducible build. Two separate builds, even from identical source, can resolve different dependency versions if a package registry served something new between builds, or pull a patched base image that changed underneath you. Tests that passed against Tuesday&#8217;s staging build tell you nothing definitive about Wednesday&#8217;s production build, because they&#8217;re not actually the same bytes.<\/p>\n<p>Fix: build the artifact exactly once, push it to a registry, and promote that identical artifact through every environment. Anything that needs to differ between staging and production, a database URL, a feature flag, a secret, gets injected at deploy time through configuration, never baked into the image at build time.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">yaml<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-yaml\">\n\nstages:\n\n  \u2013 build\n\n  \u2013 test\n\n  \u2013 promote-staging\n\n  \u2013 promote-prod\nbuild:\n\n  stage: build\n\n  script:\n\n    \u2013 docker build -t registry.example.com\/app:$CI_COMMIT_SHA .\n\n    \u2013 docker push registry.example.com\/app:$CI_COMMIT_SHA\ntest:\n\n  stage: test\n\n  script:\n\n    \u2013 docker run registry.example.com\/app:$CI_COMMIT_SHA npm test\npromote-staging:\n\n  stage: promote-staging\n\n  script:\n\n    # same tag, no rebuild\n\n    \u2013 kubectl set image deploy\/app app=registry.example.com\/app:$CI_COMMIT_SHA -n staging\n\n    \u2013 .\/scripts\/smoke-test.sh staging\npromote-prod:\n\n  stage: promote-prod\n\n  when: manual\n\n  script:\n\n    \u2013 kubectl set image deploy\/app app=registry.example.com\/app:$CI_COMMIT_SHA -n prod\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Your unit test suite takes 47 minutes on every push, and engineers have quietly started skipping local runs entirely, just pushing and waiting for CI. How do you fix the feedback loop without cutting coverage?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Testing<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Forty-seven minutes is roughly where people give up and start pushing blind, so the fix has to attack that number directly. Parallelize and shard the suite across multiple runners instead of one long serial run. Cache dependencies so every run doesn&#8217;t reinstall the same packages. Split by scope: run only the tests touching changed files (or their dependency graph) on every push, and reserve the full suite for a scheduled nightly run or the merge to main itself.<\/p>\n<p>I don&#8217;t have solid data on exactly where the tipping point sits for every team, but 47 minutes matches what I&#8217;ve seen anecdotally more than once. Somewhere past the 20 to 30 minute mark, people stop trusting the feedback loop and start treating CI as a slower, more annoying version of their own judgment.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">A canary release at 5 percent of traffic shows error rate up 2 points versus baseline. Ramp forward, or pull it back? Walk through the actual decision.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Deployment Strategy<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The decision shouldn&#8217;t be made in the moment at all, it should already be automated before the canary ever shipped. A predefined threshold tied to an error budget (say, error rate more than X percent above baseline, sustained for Y minutes) triggers an automatic rollback, no human eyeballing a dashboard under pressure and rationalizing &#8220;it&#8217;s probably noise.&#8221;<\/p>\n<p>I&#8217;ve watched more bad canaries get promoted because someone stared at a graph for 90 seconds and decided a bump was probably fine, than because an automated gate actually failed. Automate the decision before the canary ships. Don&#8217;t invent it live while traffic is already flowing to the new version.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">You shipped a database migration alongside application code in the same pull request. The new version has a bug and you need to roll back. What&#039;s the actual problem?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Rollback<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Rolling back the app without rolling back the migration leaves old code running against a new schema, missing columns, renamed fields, or worse, a column that still exists but now means something different. The fix is the expand and contract pattern: migrations add before they remove, and stay backward-compatible long enough that both the old and new app versions can run against the same schema during the transition. Only drop the old column once the new version has been running clean for a while.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">bash<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-bash\">\n\n# rollback the deployment, not just a redeploy of an older tag\n\nkubectl rollout undo deployment\/checkout-service -n prod\n# confirm which revision it landed on\n\nkubectl rollout history deployment\/checkout-service -n prod\n# the migration itself is NOT touched by this command,\n\n# which is exactly the gap this question is testing for\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the actual fix for a pipeline that holds a long-lived cloud credential just to run its own deploy step?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Secrets<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Workload identity federation, OIDC in most setups. GitHub Actions&#8217; OIDC provider can exchange a short-lived token for a scoped cloud role at run time, so no static access key sits in the pipeline&#8217;s secret store at all. If a token leaks, it&#8217;s usually already expired by the time anyone finds it.<\/p>\n<p>My take that might be wrong: most teams still treat this as an advanced, nice-to-have setup, when it should be the default for any pipeline touching production cloud resources. A leaked long-lived key is a bigger practical risk than most of the rollback scenarios covered earlier on this page, and it gets a fraction of the interview time.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Rolling your own deploy step with kubectl apply from CI, versus adopting Argo CD or Flux, what&#039;s the real operational trade-off?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">GitOps<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>kubectl-apply-from-CI is simpler for a small team to reason about, one fewer system to run and patch, but every rollback becomes a brand new CI run, and cluster credentials sit in the pipeline the whole time. Argo CD or Flux add an in-cluster component someone has to operate and upgrade, plus a learning curve around sync policies and health checks, but they buy continuous drift detection and a rollback that&#8217;s genuinely just a git revert.<\/p>\n<p>My honest opinion: for a single small cluster with two engineers on call, plain CI pushing kubectl apply is probably fine, and bolting on Argo CD there is closer to complexity theater than a real improvement. It starts paying for itself once more than a handful of clusters, or more than one team, are touching the same manifests.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">A team deploys to production twice a day, lead time under two hours, but their mean time to recovery is six hours. What does that combination actually tell you?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">DORA Metrics<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Strong throughput, weak stability. The team ships fast but doesn&#8217;t detect or respond to a bad deploy quickly, which points at a gap in automated rollback triggers, canary analysis, or alerting tied to real SLOs, not a &#8220;deploy less often&#8221; fix. Interviewers want to hear that diagnosis named directly instead of a vague &#8220;improve monitoring&#8221; answer.<\/p>\n<p>Worth knowing: DORA&#8217;s own 2025 report actually walked back the old Elite, High, Medium, Low ranking model it had used for a decade, replacing it with seven team archetypes that blend delivery performance with human factors like burnout and friction, because two teams with identical metrics can be in very different health states. I genuinely don&#8217;t know yet whether the archetype model will stick past one report cycle. It&#8217;s worth remembering next time a hiring rubric asks whether you&#8217;re a &#8220;high performer&#8221; as if that&#8217;s a fixed score.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Your merge queue is stalled: forty PRs are queued, and every batch that includes a certain flaky integration test fails, kicking the whole batch back and re-running from scratch. How do you actually fix the throughput problem, not just the flaky test?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Merge Queue Failure<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The immediate operational fix is to stop treating the queue as one atomic unit that lives or dies together. A well-designed merge queue should isolate failures with a bisection strategy. When a batch of five PRs fails CI, instead of kicking every PR in that batch back to the end of the line, split the batch and retest the halves, and keep splitting until you isolate which specific PR, or in this case confirm it&#8217;s not any individual PR but a flaky test unrelated to all of them, is responsible. GitHub&#8217;s merge queue and Graphite&#8217;s merge queue both support this kind of batch splitting specifically because naive whole-batch-fails whole-batch-requeues throughput collapses under exactly this scenario. One flaky test can fail every batch it happens to land in, and every failure means dozens of PRs&#8217; worth of CI time gets thrown away and restarted.<\/p>\n<p>The actual root cause fix is separating must-pass-to-merge from nice-to-have-passing. If that integration test is genuinely flaky, confirmed by re-running it in isolation against an unchanged commit and seeing it fail intermittently, it needs to come out of the queue&#8217;s blocking gate immediately, even before a real fix lands, and get quarantined into a non-blocking job that still reports failures for someone to investigate. Leaving a known-flaky test in the blocking path of a merge queue means every single PR pays the tax of that flakiness, a much bigger cost than the risk of merging without that one test blocking for a few days while it&#8217;s fixed properly.<\/p>\n<p>Longer term, this is also a signal to look at the test itself. Integration tests that are flaky under queue conditions specifically, versus flaky when run alone, often point to shared state or a shared resource, a test database, a rate-limited external API, a fixed port, that multiple batches in the queue are contending for concurrently. Fixing that contention, isolated databases per test run, retry logic with backoff for genuinely flaky external dependencies, unique ports or namespaces per parallel job, usually fixes the flakiness at the source rather than needing an increasingly clever queue-management workaround to route around it forever.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Walk through how a CI supply chain attack like the tj-actions\/changed-files compromise actually works, and what specific pipeline hardening would have limited the blast radius.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Supply Chain Attack<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The attack pattern is consistent across incidents like this. An attacker compromises a widely used, low-scrutiny dependency, in this case a GitHub Action, either by compromising a maintainer&#8217;s credentials or by getting a malicious PR merged, and then modifies what the mutable version tag points to. Any workflow referencing that action by tag, @v45 say, rather than a pinned SHA, picks up the malicious code on its very next run with no review, no PR, nothing in your own repo&#8217;s history to flag it. The payload in that specific case dumped CI secrets, environment variables including things like AWS keys and npm tokens, into the workflow&#8217;s build logs, which are often visible to anyone with read access to the repo, or even public for open source projects.<\/p>\n<p>The specific hardening steps that limit this: pin every third-party action to a commit SHA, not a tag, so a retag doesn&#8217;t silently change what runs. Scope secrets tightly, a workflow that only needs to run tests shouldn&#8217;t have a token that can push to the container registry or deploy to production, so a compromised test job can&#8217;t pivot to a full deploy. Use OIDC-based short-lived cloud credentials instead of long-lived static secrets stored as repo secrets, so even a successful log-dumping attack captures a token that expires in minutes rather than a key that&#8217;s valid until someone manually rotates it. And treat workflow logs as sensitive by default, don&#8217;t echo environment variables for debugging in a job that has real secrets loaded, since that&#8217;s precisely the exfiltration path this class of attack relies on.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">You&#039;ve got a deploy that passed every CI check and looks identical to last week&#039;s successful deploy, but the new pods are crash-looping in production with an error that never showed up in staging. CI used the exact same Dockerfile. Walk through how you&#039;d actually debug this.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Build Reproducibility<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The first thing I&#8217;d check is whether the build is actually reproducible, meaning does the Dockerfile pin every base image and dependency to an exact, immutable reference, or does anything resolve dynamically at build time. A shockingly common cause here is a base image tag like node:20, not node:20.11.0-bookworm, and definitely not the digest, that silently points to a newer minor version today than it did last week, because the upstream maintainer pushed a new image to that tag. Staging built successfully last week against the old resolved image. Today&#8217;s production build, run at a different time, pulled a genuinely different base image even though the Dockerfile text hasn&#8217;t changed and CI reports green, because the tests that ran were against whatever got resolved at that build time, not against a fixed artifact.<\/p>\n<p>The second suspect, if the base image is pinned, is a build-time versus run-time environment mismatch. Does the CI runner&#8217;s architecture match production, an Apple Silicon dev laptop building an arm64 image that then gets deployed to amd64 nodes is a classic one, or does a dependency resolve differently because a lockfile is missing or not being respected, npm install instead of npm ci, or a Python requirements.txt without pinned transitive versions letting pip resolve a newer sub-dependency today than yesterday.<\/p>\n<p>The actual debugging move is to stop trusting that an identical Dockerfile proves reproducibility and instead diff what&#8217;s literally inside the two images, docker image inspect for the base layers, and something like dive or just an apt list installed or pip freeze inside both the working and crash-looping container, to find the actual delta. Once you find it, the long-term fix is pinning by digest for the base image and locking every dependency manifest, so the same Dockerfile actually means the same bytes going forward.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why is eyeballing a canary&#039;s error-rate dashboard against baseline not enough at low traffic, and how would you design an automated canary analysis step that avoids that trap?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Canary Analysis<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>At low sample sizes, noise looks exactly like signal. If your canary gets 200 requests a minute and baseline gets 4,000, a canary error rate that ticks up from 0.5 percent to 1.2 percent could be three failed requests instead of two, a difference completely within normal statistical noise for that sample size, but on a dashboard it visually reads as error rate more than doubled. An engineer eyeballing that number under pressure during a rollout will very reasonably pull the canary back for what&#8217;s actually just noise, or worse, will get used to seeing noisy jumps and start ignoring real regressions because the canary numbers always bounce around.<\/p>\n<p>An automated canary analysis step, this is what tools like Kayenta, built for this exact problem at Netflix and Google, or Argo Rollouts&#8217; analysis templates do, needs to run a real statistical comparison, not a threshold check on a raw percentage. Concretely: pull the same metric, error rate, p99 latency, for canary and baseline over the same time window, run a significance test, Mann-Whitney U is common because it doesn&#8217;t assume a normal distribution, which latency and error-rate data usually aren&#8217;t, and only fail the canary if the difference is both statistically significant and above a meaningful effect-size threshold, since with enough samples you can find a significant difference that&#8217;s practically irrelevant, a 0.001 percent latency increase that&#8217;s real but doesn&#8217;t matter.<\/p>\n<p>The traffic allocation matters just as much as the analysis. A canary needs enough real traffic and enough time to accumulate a sample where the math actually has power to detect a real regression, which is why canaries usually ramp, 1 percent for a few minutes, then 5 percent, then 25 percent, rather than jumping straight to a fixed split, and why teams building this seriously score confidence per metric and require several consecutive analysis intervals to pass, not just one snapshot, before promoting.<\/p>\n<p><\/div><\/div><\/div>\n<h2>How to prepare for CI\/CD interview questions in 2026<\/h2>\n<p>Skip another flashcard pass on wait, another blue-green definition you can already recite. Build a small pipeline yourself, GitHub Actions is the fastest to set up for a side project, then deliberately break it: tag an image &#8216;latest&#8217; instead of by SHA, skip the post-deploy health check, hardcode a secret into a config file. Fixing your own mistakes teaches the failure modes faster than reading about them ever will.<\/p>\n<p>Interviewers weight the &#8220;why&#8221; behind a decision far more than exact syntax, and a good number of these loops run on a shared screen with no autocomplete, so practice writing a pipeline YAML file cold. If you don&#8217;t have production CI\/CD experience yet, a personal project with a real deploy step, even a tiny one, beats reciting definitions, because an interviewer can tell the difference between &#8220;I read about this&#8221; and &#8220;I broke this once and had to fix it myself.&#8221;<\/p>\n<h2>Practice the pipeline questions before the real one<\/h2>\n<p>Reading an answer about a stale canary or a botched rollback is not the same as defending it live once an interviewer changes one variable on you. <a href=\"\/products\/mock-interviews\">LastRoundAI&#8217;s mock interview mode<\/a> runs CI\/CD and platform engineering rounds with real-time follow-up questions instead of a static bank, and the free plan includes 15 credits a month that reset monthly rather than stockpiling. Starter is $19 a month if you want more sessions than that covers.<\/p>\n<p>If the slower part of the job hunt is actually finding enough DevOps or platform roles rather than passing the interview once you land one, <a href=\"\/products\/auto-apply\">Auto-Apply<\/a> matches and applies to roles for you, 10 a month on the free plan, up to 400 a month on the Ultimate plan, with every application held in a review queue until you approve it. Nothing goes out on your behalf without you looking at it first. There&#8217;s no native mobile app yet, just a desktop app and a browser that works fine from a phone.<\/p>\n<p>Questions about either product go to contact@lastroundai.com. That&#8217;s the only inbox we check.<\/p>\n<div class=\"iq-sources not-prose\"><div class=\"iq-sources__title\">Sources &amp; further reading<\/div><ul class=\"iq-sources__list\"><li><a href=\"https:\/\/dora.dev\/research\/2024\/dora-report\/\" target=\"_blank\" rel=\"nofollow noopener\">DORA: Accelerate State of DevOps Report 2024<\/a><\/li><li><a href=\"https:\/\/blog.jetbrains.com\/teamcity\/2025\/10\/the-state-of-cicd\/\" target=\"_blank\" rel=\"nofollow noopener\">JetBrains: The State of CI\/CD in 2025<\/a><\/li><li><a href=\"https:\/\/opengitops.dev\/\" target=\"_blank\" rel=\"nofollow noopener\">OpenGitOps Principles (CNCF GitOps Working Group)<\/a><\/li><\/ul><\/div>\n","protected":false},"excerpt":{"rendered":"<p>A senior SRE candidate at a fintech startup gave a clean, textbook answer on blue-green deployments in March 2026, then lost the offer two questions later. The interviewer asked what happens to in-flight database connections during the traffic switch. He hadn&#8217;t thought about it, because most tutorials stop at &#8220;traffic moves from blue to green&#8221;&#8230;<\/p>\n","protected":false},"author":5,"featured_media":1633,"comment_status":"open","ping_status":"closed","template":"","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"tags":[],"class_list":["post-1152","iq","type-iq","status-publish","has-post-thumbnail","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>CI\/CD Interview Questions (2026) | LastRoundAI<\/title>\n<meta name=\"description\" content=\"Prep CI\/CD interview questions on pipelines, blue-green vs canary deploys, rollback, secrets, GitOps, and DORA metrics. Practice free with LastRoundAI.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/lastroundai.com\/interview-questions\/ci-cd\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"CI\/CD Interview Questions (2026) | LastRoundAI\" \/>\n<meta property=\"og:description\" content=\"Prep CI\/CD interview questions on pipelines, blue-green vs canary deploys, rollback, secrets, GitOps, and DORA metrics. Practice free with LastRoundAI.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/lastroundai.com\/interview-questions\/ci-cd\" \/>\n<meta property=\"og:site_name\" content=\"LastRound AI\" \/>\n<meta property=\"og:image\" content=\"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-ci-cd-og.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"54 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/ci-cd\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/ci-cd\",\"name\":\"CI\\\/CD Interview Questions (2026) | LastRoundAI\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/ci-cd#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/ci-cd#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/iq-ci-cd-og.png\",\"datePublished\":\"2026-07-23T08:35:00+00:00\",\"description\":\"Prep CI\\\/CD interview questions on pipelines, blue-green vs canary deploys, rollback, secrets, GitOps, and DORA metrics. Practice free with LastRoundAI.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/ci-cd#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/ci-cd\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/ci-cd#primaryimage\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/iq-ci-cd-og.png\",\"contentUrl\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/iq-ci-cd-og.png\",\"width\":1200,\"height\":630,\"caption\":\"CI\\\/CD interview questions \u2014 LastRoundAI\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/ci-cd#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/lastroundai.com\\\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Interview Questions\",\"item\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"CI\\\/CD Interview Questions (2026): Pipelines, Must-Know Q&#038;A\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/\",\"name\":\"LastRound AI\",\"description\":\"Interview Assistant prep, tech careers and AI tools\",\"publisher\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#organization\",\"name\":\"LastRound AI\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png\",\"contentUrl\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png\",\"width\":400,\"height\":400,\"caption\":\"LastRound AI\"},\"image\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"CI\/CD Interview Questions (2026) | LastRoundAI","description":"Prep CI\/CD interview questions on pipelines, blue-green vs canary deploys, rollback, secrets, GitOps, and DORA metrics. Practice free with LastRoundAI.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/lastroundai.com\/interview-questions\/ci-cd","og_locale":"en_US","og_type":"article","og_title":"CI\/CD Interview Questions (2026) | LastRoundAI","og_description":"Prep CI\/CD interview questions on pipelines, blue-green vs canary deploys, rollback, secrets, GitOps, and DORA metrics. Practice free with LastRoundAI.","og_url":"https:\/\/lastroundai.com\/interview-questions\/ci-cd","og_site_name":"LastRound AI","og_image":[{"width":1200,"height":630,"url":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-ci-cd-og.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"54 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/lastroundai.com\/interview-questions\/ci-cd","url":"https:\/\/lastroundai.com\/interview-questions\/ci-cd","name":"CI\/CD Interview Questions (2026) | LastRoundAI","isPartOf":{"@id":"https:\/\/lastroundai.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/lastroundai.com\/interview-questions\/ci-cd#primaryimage"},"image":{"@id":"https:\/\/lastroundai.com\/interview-questions\/ci-cd#primaryimage"},"thumbnailUrl":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-ci-cd-og.png","datePublished":"2026-07-23T08:35:00+00:00","description":"Prep CI\/CD interview questions on pipelines, blue-green vs canary deploys, rollback, secrets, GitOps, and DORA metrics. Practice free with LastRoundAI.","breadcrumb":{"@id":"https:\/\/lastroundai.com\/interview-questions\/ci-cd#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/lastroundai.com\/interview-questions\/ci-cd"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/lastroundai.com\/interview-questions\/ci-cd#primaryimage","url":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-ci-cd-og.png","contentUrl":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-ci-cd-og.png","width":1200,"height":630,"caption":"CI\/CD interview questions \u2014 LastRoundAI"},{"@type":"BreadcrumbList","@id":"https:\/\/lastroundai.com\/interview-questions\/ci-cd#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/lastroundai.com\/blog"},{"@type":"ListItem","position":2,"name":"Interview Questions","item":"https:\/\/lastroundai.com\/interview-questions"},{"@type":"ListItem","position":3,"name":"CI\/CD Interview Questions (2026): Pipelines, Must-Know Q&#038;A"}]},{"@type":"WebSite","@id":"https:\/\/lastroundai.com\/blog\/#website","url":"https:\/\/lastroundai.com\/blog\/","name":"LastRound AI","description":"Interview Assistant prep, tech careers and AI tools","publisher":{"@id":"https:\/\/lastroundai.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/lastroundai.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/lastroundai.com\/blog\/#organization","name":"LastRound AI","url":"https:\/\/lastroundai.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/lastroundai.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/06\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png","contentUrl":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/06\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png","width":400,"height":400,"caption":"LastRound AI"},"image":{"@id":"https:\/\/lastroundai.com\/blog\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq\/1152","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq"}],"about":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/types\/iq"}],"author":[{"embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/comments?post=1152"}],"version-history":[{"count":3,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq\/1152\/revisions"}],"predecessor-version":[{"id":1745,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq\/1152\/revisions\/1745"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/media\/1633"}],"wp:attachment":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/media?parent=1152"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/tags?post=1152"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}