These GitLab CI/CD interview questions cover what hiring panels actually probe in 2026: whether you can write a correct .gitlab-ci.yml, explain why a pipeline behaves the way it does, and fix it when it is slow, stuck or leaking secrets. Interviewers rarely stop at "what is a runner"; they hand you a pending job, a cache that never restores or a deploy that hit the wrong environment, and listen to how you reason through it. The 60 questions below move from fundamentals to rules, DAGs, components, merge trains, runners, OIDC, security scanning, GitLab Duo and thirteen real-world scenarios.
How to use this guide:
- Freshers are usually tested on pipelines, stages, jobs, runners, artifacts versus cache, variables and environments. Be able to write a three-stage pipeline from memory.
- Engineers with two to five years get
rules,workflow:rules,needs,include/extends, merge request pipelines, protected variables, runners and at least two troubleshooting scenarios. - Senior and platform roles are pushed on CI/CD components and the catalog,
spec:inputs, parent-child and multi-project design, merge trains, runner fleets, OIDC to cloud providers, compliance enforcement and pipeline speed at scale. - Product details change often. Where a feature depends on your subscription, this guide says "check your tier" rather than guessing. Treat the YAML here as patterns and confirm details against the GitLab documentation for your version.
Contents
- GitLab CI/CD fundamentals (Q1โQ10)
- Intermediate .gitlab-ci.yml questions (Q11โQ27)
- Advanced pipelines, runners and architecture (Q28โQ42)
- Security scanning in GitLab pipelines (Q43โQ44)
- GitLab vs GitHub Actions vs Jenkins, and AI in GitLab CI/CD (Q45โQ47)
- GitLab CI/CD scenario based questions (Q48โQ60)
- Key takeaways
- Interview preparation checklist
- FAQ
GitLab CI/CD fundamentals
1. What is GitLab CI/CD, and how does it work?
Answer: GitLab CI/CD is the continuous integration and delivery system built into GitLab. You describe a pipeline in a .gitlab-ci.yml file in the repository; when an event happens (a push, a merge request, a tag, a schedule, an API call), GitLab evaluates that file, creates a pipeline of jobs, and queues them. Runners poll GitLab, pick up jobs that match them, execute the job's script in a shell, container or VM, stream the log back, and upload artifacts. GitLab then records the result against the commit, the merge request and, for deploy jobs, the environment.
Because the repository, merge requests, pipelines, container registry, environments and security reports live in one product, the pipeline result is visible exactly where the review happens. That single-application model is the main reason teams choose GitLab.
Interview tip: People sometimes search for "GitLab Actions", but that is not a GitLab product. GitHub has Actions; GitLab has CI/CD pipelines and jobs. Using the right vocabulary signals hands-on experience.
2. What is the .gitlab-ci.yml file, where does it live, and how do you validate it?
Answer: It is the YAML file that defines the pipeline: stages, jobs, scripts, images, variables, rules, artifacts, cache and includes. By default it lives at the root of the repository, although the project's CI/CD settings let you point to a different path or even a file in another project. Every pipeline uses the version of the file at the commit being built, so configuration changes go through review like code.
To validate it, use the pipeline editor in the GitLab UI (it lints as you type and shows the full merged configuration after includes), or the CI Lint tool/API. The merged view is the important part: most "my job doesn't run" problems come from an include or extends you forgot about.
stages: [build, test, deploy]
default:
image: node:22
build:
stage: build
script:
- npm ci
- npm run build
artifacts:
paths: [dist/]
test:
stage: test
script:
- npm test
deploy:
stage: deploy
script:
- ./deploy.sh
environment: production
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
3. Explain pipelines, stages and jobs.
Answer: A pipeline is one run of the configuration for one commit or event. A job is the unit of work: a script with an image, variables and rules, executed by one runner. A stage groups jobs. By default, jobs in the same stage run in parallel, and the next stage starts only when every job in the previous stage has succeeded (or is allowed to fail). If you do not declare stages, GitLab uses the defaults .pre, build, test, deploy, .post.
With needs (Q14), a job can start as soon as its specific dependencies finish, turning the pipeline into a DAG.
4. What is a GitLab Runner, and what are instance, group and project runners?
Answer: GitLab Runner is the agent application that executes jobs. GitLab itself only schedules; runners do the work. Runners are scoped three ways:
- Instance runners are available to every project on the GitLab instance. GitLab-hosted runners on GitLab.com are instance runners. Older material calls these "shared runners".
- Group runners serve all projects in a group and its subgroups.
- Project runners serve one project (or a few you explicitly enable).
Separately, runners are either GitLab-hosted (managed by GitLab, a fresh VM per job, Linux, Windows and macOS options) or self-managed (installed on your own servers, VMs or Kubernetes). Jobs reach a specific runner through tags: a job with tags: [linux, docker] only runs on a runner carrying those tags.
Real-world example: Consider a bank's GCC team in Hyderabad that uses GitLab-hosted runners for open-source linting but registers a self-managed group runner inside its VPC for jobs that need private network access to databases and artifact stores.
5. What runner executors exist, and how do you choose one?
Answer: The executor decides where the job's script runs. Current GitLab Runner documentation lists Docker, Docker Autoscaler, Instance and Kubernetes as the actively developed executors; Shell, SSH, VirtualBox, Parallels and Custom are in maintenance mode (security fixes, no new features); and Docker Machine is deprecated.
| Executor | Good for | Watch out for |
|---|---|---|
| Docker | Clean, reproducible job containers on one host | Disk fills with images and volumes; privileged mode for Docker-in-Docker |
| Kubernetes | Each job as a pod in a cluster; elastic | Pod resource requests, node autoscaling lag, service account permissions |
| Docker Autoscaler / Instance | Autoscaling VMs in a cloud via fleeting plugins | Cloud quotas, idle capacity settings, cost |
| Shell | Legacy builds needing host tools | No isolation; state leaks between jobs |
6. What types of pipelines does GitLab support?
Answer:
- Branch pipelines: run on pushes to a branch (
$CI_COMMIT_BRANCHis set). - Tag pipelines: run when a tag is pushed (
$CI_COMMIT_TAG), common for releases. - Merge request pipelines: run in the context of a merge request (
$CI_PIPELINE_SOURCE == "merge_request_event"). - Merged results pipelines: test the result of merging source into target before the merge happens.
- Merge train pipelines: queue merges and test each against everything ahead of it (Q32).
- Scheduled pipelines: cron-like schedules, for nightly builds or dependency rescans.
- Parent-child and multi-project pipelines: downstream pipelines triggered by a
triggerjob. - API, trigger-token and manual pipelines: started from outside or from the "Run pipeline" button.
Merged results pipelines and merge trains depend on your subscription, so check your tier before designing around them.
7. What is the difference between cache and artifacts?
Answer: GitLab's own guidance is the clearest line: use cache for dependencies, such as packages downloaded from the internet, and artifacts to pass intermediate build results between stages and jobs. The differences that matter in practice:
| Cache | Artifacts | |
|---|---|---|
| Purpose | Speed up repeated work | Hand outputs to later jobs, download, reports |
| Stored | On the runner, or a distributed cache (S3-compatible) if configured | Uploaded to GitLab |
| Always present? | No; a job must still work when the cache is missing | Yes, until expire_in |
| Scope | Shared across pipelines by cache key | Belongs to the job and pipeline that produced it |
Interview tip: Never pass a compiled binary through cache. If the next job lands on a different runner without a distributed cache, it simply is not there.
8. What are CI/CD variables, and where can they be defined?
Answer: Variables are key-value pairs exposed to jobs as environment variables. Predefined variables come from GitLab (CI_COMMIT_SHA, CI_COMMIT_REF_SLUG, CI_PIPELINE_SOURCE, CI_DEFAULT_BRANCH, CI_REGISTRY_IMAGE). Custom variables can be set in .gitlab-ci.yml (global or per job), in project, group or instance settings, as pipeline variables at run time, or through a dotenv artifact report from an earlier job. Settings variables can be file type, so the job receives a path to a temp file, which suits kubeconfigs and certificates.
Precedence matters: in GitLab's documented order, variables from settings (project, group, instance) override variables written in .gitlab-ci.yml, and pipeline and manual-job variables override both. Never put secrets in the YAML file; it is versioned and visible to everyone with read access.
9. How do default, before_script, after_script, allow_failure and when work?
Answer: default: sets shared values (image, before_script, after_script, cache, retry, tags, interruptible) for all jobs; defining image or before_script at the top level without default is the deprecated form. before_script runs before the job's script in the same shell; after_script runs in a separate shell afterwards, even when the job fails, so it suits cleanup and diagnostics but should not be relied on for anything that must succeed.
allow_failure: true lets a job fail without failing the pipeline (useful for an experimental linter). when controls when a job runs: on_success (default), on_failure, always, manual, delayed or never. A rollback job is a normal job with when: on_failure or when: manual; there is no on_failure: block inside a job, a mistake that appears in many older interview answers.
rollback:
stage: deploy
script:
- ./rollback.sh
environment: production
when: on_failure
10. What are environments and deployments in GitLab?
Answer: An environment is a named deployment target (development, staging, production, or a dynamic one per branch). A job that declares environment: becomes a deploy job, and each run creates a deployment record. That gives you a history of what commit is running where, a link to the app via url, one-click re-deploy of an earlier deployment for rollback, and environment-scoped variables so the production database password is only exposed to jobs deploying to production.
GitLab infers a deployment_tier (production, staging, testing, development, other) from the name, or you set it explicitly. Useful related keywords are on_stop, action: stop, auto_stop_in and kubernetes:agent.
Intermediate .gitlab-ci.yml questions
11. What is the difference between rules and only/except, and what is the status of only/except?
Answer: Both decide whether a job is added to a pipeline. only/except are listed in GitLab's deprecated keywords: still usable for backward compatibility but not recommended, with rules as the replacement. rules is an ordered list evaluated top to bottom; the first matching rule wins and sets when, allow_failure, variables or needs for that case. If no rule matches, the job is not added.
deploy_prod:
script: ./deploy.sh production
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
when: never
- if: $CI_COMMIT_TAG
when: manual
- when: never
Interview tip: You cannot mix rules with only/except in the same job. Say you would migrate a job at a time and compare the merged configuration before and after.
12. What is workflow:rules, and how do you avoid duplicate branch and merge request pipelines?
Answer: rules decide jobs; workflow:rules decide whether the whole pipeline is created at all, and can set pipeline-level variables or a pipeline name. The classic problem: pushing to a branch with an open merge request creates two pipelines, one branch pipeline and one merge request pipeline. GitLab documents this pattern to switch between them:
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
Merge request events get a pipeline; a branch push is skipped if that branch has an open merge request; otherwise branch pipelines run. workflow also hosts auto_cancel settings (Q23).
13. How do rules:changes and rules:exists work, and what is the branch-pipeline gotcha?
Answer: rules:changes adds a job only when listed files changed; rules:exists adds it only when files exist in the repository (for example, run Docker build only if a Dockerfile exists). The gotcha: in merge request pipelines, changes are compared against the target branch, which is what you expect. In branch pipelines and on new branches, the comparison base is the previous push, so a first push or a force-push can make changes evaluate to true for everything. rules:changes:compare_to lets you pin the comparison to a ref such as the default branch.
api_tests:
script: make test-api
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
paths:
- services/api/**/*
compare_to: refs/heads/main
14. What does needs do, and how is it different from dependencies?
Answer: needs defines execution order explicitly, so a job starts as soon as the jobs it needs finish, regardless of stage. This creates a DAG; jobs can even need jobs in the same stage. needs: [] makes a job start immediately. needs also controls artifact download: by default a job downloads artifacts from the jobs it needs, and needs:artifacts: false skips that. needs:optional: true handles a needed job that rules may exclude.
dependencies only controls which artifacts are downloaded; it does not change when the job starts. Setting dependencies: [] on a job that needs no files avoids downloading large artifacts it does not use.
unit_test:
stage: test
needs: [build_backend]
script: make test
lint:
stage: test
needs: []
script: make lint
15. How do parallel and parallel:matrix work?
Answer: parallel: 5 runs five copies of the same job, each with CI_NODE_INDEX and CI_NODE_TOTAL, which test runners use to split a suite. parallel:matrix generates one job per combination of variable values:
test:
image: python:$PY_VERSION
script:
- pip install -r requirements.txt
- pytest
parallel:
matrix:
- PY_VERSION: ["3.11", "3.12", "3.13"]
DB: [postgres, mysql]
That produces six jobs. Matrix values can also select runner tags, which is a neat way to fan out across regions or architectures.
16. What can include import, and when would you use each type?
Answer: include merges external YAML into the pipeline. Types: local (a file in the same repository), project (a file in another project, pinned with ref), remote (a URL), template (GitLab-maintained templates such as security scanners) and component (a versioned CI/CD component, Q30). Includes can carry inputs and can be conditional with include:rules.
include:
- local: ci/build.yml
- project: platform/ci-templates
ref: v3.2.0
file: /templates/deploy.yml
- template: Jobs/SAST.gitlab-ci.yml
Production consideration: Pin project includes to a tag or SHA, not a branch. An unpinned shared template means someone else's commit can change your production deploy without a merge request in your project. Avoid remote includes from hosts you do not control.
17. Compare extends, YAML anchors and !reference tags.
Answer: All three reduce duplication. YAML anchors (&, *, <<) are plain YAML and only work within one file, not across included files. extends is GitLab's inheritance: a job inherits from one or more (often hidden, dot-prefixed) jobs, works across includes, and deep-merges hashes, though arrays such as script are replaced rather than appended. !reference picks a specific section from another job, even from an included file, and is the way to reuse a few script lines:
.aws_login:
before_script:
- ./scripts/aws-login.sh
deploy:
extends: .deploy_base
script:
- !reference [.aws_login, before_script]
- ./deploy.sh
Rule of thumb: extends for job templates, !reference for script snippets, anchors only for small single-file cases. Note that !reference and inputs cannot be combined.
18. How do you configure cache well?
Answer: Choose a key that changes when the dependencies change, keep paths inside the project directory, and make most jobs read-only consumers.
.node_cache:
cache:
key:
files: [package-lock.json]
paths: [.npm/]
policy: pull
fallback_keys:
- npm-$CI_DEFAULT_BRANCH
install_deps:
extends: .node_cache
cache:
policy: pull-push
script:
- npm ci --cache .npm --prefer-offline
cache:key:files builds the key from the lockfile's content, policy: pull stops every job from re-uploading the cache, and fallback_keys (or the global CACHE_FALLBACK_KEY variable) gives a warm start when the exact key is new. Cache the package manager's download directory rather than node_modules when tools recommend a clean install.
19. What can artifacts do beyond passing files?
Answer: Artifacts can be downloaded from the UI, expire with expire_in, upload on failure with when: always (ideal for test screenshots and logs), and feed GitLab features through artifacts:reports: junit for test results in the merge request widget, coverage reports, security scanner reports, and dotenv, which turns a file of KEY=value lines into variables for later jobs.
test:
script: pytest --junitxml=report.xml
artifacts:
when: always
expire_in: 1 week
reports:
junit: report.xml
build:
script:
- echo "IMAGE_TAG=$CI_COMMIT_SHORT_SHA" > build.env
artifacts:
reports:
dotenv: build.env
20. What is the difference between merge request pipelines and merged results pipelines?
Answer: A merge request pipeline runs on the source branch's commit in the context of the merge request; jobs opt in with $CI_PIPELINE_SOURCE == "merge_request_event". It can still miss breakage caused by changes that landed on the target branch since you branched. A merged results pipeline runs against a temporary merge commit of source plus current target, so it tests what would actually land. Merged results pipelines are a prerequisite for merge trains and are tier-dependent, so check your tier.
Production consideration: For merge requests from forks, the pipeline runs in the fork by default. Running it in the parent project exposes parent secrets to untrusted code, so a maintainer must review the change first. GitLab warns before you run it.
21. What are protected, masked and hidden variables, and what are their limits?
Answer: A protected variable is only passed to pipelines on protected branches or protected tags, so a feature branch cannot read the production deploy key. A masked variable is replaced with [MASKED] in job logs; the value must meet GitLab's masking requirements (at least eight characters, a single line, a restricted character set). Masked and hidden additionally hides the value in the settings UI after creation, so even maintainers cannot read it back; it can only be chosen when the variable is created.
The limits: GitLab's documentation is explicit that masking cannot reliably stop a malicious user from reading a value. Anything that transforms the value (base64, URL-encoding, splitting, shell escaping) defeats the log filter, and any code running in the job can send the value elsewhere. Protection and scoping (who can run the job) matter more than masking (what the log shows).
22. How do scheduled pipelines and pipeline trigger tokens work?
Answer: Pipeline schedules run a pipeline on a ref with a cron expression and timezone, optionally with schedule-specific variables; jobs detect them with $CI_PIPELINE_SOURCE == "schedule". Typical uses: nightly integration suites, dependency and container rescans, cleanup jobs. Pipeline trigger tokens let an external system start a pipeline through the API ($CI_PIPELINE_SOURCE == "trigger"). Inside GitLab, prefer the trigger keyword for downstream pipelines rather than calling the API with a token.
23. What do interruptible and workflow:auto_cancel do?
Answer: When a new commit arrives on the same branch, older pipelines become redundant. interruptible: true marks a job as safe to cancel in that case (builds, tests, linters). workflow:auto_cancel:on_new_commit chooses the policy: conservative (the default, cancels only if no non-interruptible job has started), interruptible (cancel only the interruptible jobs) or none. workflow:auto_cancel:on_job_failure: all cancels the rest of the pipeline as soon as one job fails, which saves runner time on obviously broken commits.
Never mark deploy or database migration jobs as interruptible; cancelling halfway through a migration is worse than finishing a redundant one.
24. What is resource_group, and when do you need it?
Answer: resource_group makes jobs that share a name mutually exclusive across pipelines in the project, so only one runs at a time. Two merges in quick succession would otherwise start two production deploys concurrently. With resource_group: production, the second waits. The process mode (for example oldest first or newest first) can be changed through the API, which matters if you want the latest commit to win.
deploy_prod:
script: ./deploy.sh
environment: production
resource_group: production
Pair it with the environment setting that prevents outdated deployment jobs, so an older pipeline cannot roll production back after a newer one has deployed.
25. How do you build and push container images in GitLab CI/CD?
Answer: The common approach is Docker-in-Docker with TLS, pushing to the project's built-in container registry using predefined credentials:
build_image:
image: docker:27
services:
- docker:27-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
script:
- >
echo "$CI_REGISTRY_PASSWORD" |
docker login -u "$CI_REGISTRY_USER"
--password-stdin "$CI_REGISTRY"
- docker build -t "$IMAGE" .
- docker push "$IMAGE"
Docker-in-Docker needs a privileged runner, which is a security trade-off: a privileged job can escape to the host. Alternatives are a daemonless builder (Buildah or rootless BuildKit) or a dedicated build runner pool isolated from runners with deployment credentials. Pin image versions rather than using latest, and tag images with the commit SHA so deployments are traceable. For container fundamentals, see the Docker interview questions guide.
26. What are review apps, and how are GitLab Pages different?
Answer: Review apps are dynamic environments, one per branch or merge request, so reviewers and testers can click a link and see the change running. They use variables in the environment name and URL, plus a stop job:
review:
script: ./deploy-review.sh "$CI_COMMIT_REF_SLUG"
environment:
name: review/$CI_COMMIT_REF_SLUG
url: https://$CI_COMMIT_REF_SLUG.review.example.com
on_stop: stop_review
auto_stop_in: 2 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
stop_review:
script: ./teardown-review.sh "$CI_COMMIT_REF_SLUG"
environment:
name: review/$CI_COMMIT_REF_SLUG
action: stop
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: manual
GitLab Pages is different: it hosts a static site that a job publishes as an artifact (traditionally a job named pages producing a public/ directory). Pages suits documentation and static front ends; review apps suit full applications with back ends.
27. What is Auto DevOps, and would you use it in production?
Answer: Auto DevOps is a predefined pipeline that detects the project's language and adds build, test, code quality, security scanning (SAST, dependency, container, secret detection, DAST), review apps and deployment to Kubernetes. It is not enabled by default for an instance unless an administrator turns it on, and a project's own .gitlab-ci.yml takes precedence.
It suits a quick start and shows what a complete pipeline looks like. Most production teams instead include the individual templates they want and write their own deploy jobs, because a generic deploy rarely matches real release controls.
Advanced pipelines, runners and architecture
28. When would you use parent-child pipelines, and what are dynamic child pipelines?
Answer: A parent-child pipeline lets one pipeline trigger child pipelines in the same project, ref and commit. Use it to split a large monorepo configuration into per-component files, to keep each child's DAG small, or to run a child only when its part of the code changed. With strategy: depend (or strategy: mirror), the trigger job reflects the child's status, so the parent fails if the child fails.
A dynamic child pipeline is generated at runtime: one job writes YAML as an artifact, and a trigger job runs it. This suits monorepos where a script decides which services to build.
generate:
stage: build
script: ./ci/generate-pipeline.sh > child.yml
artifacts:
paths: [child.yml]
run_child:
stage: test
trigger:
include:
- artifact: child.yml
job: generate
strategy: depend
Parent-child nesting is limited in depth, so do not design deep trees.
29. How do multi-project pipelines work?
Answer: A trigger job starts a pipeline in a different project, for example an application repository triggering an integration-test or deployment repository. The triggering user must have permission to run pipelines in the downstream project, or the downstream pipeline fails to start.
trigger_e2e:
stage: deploy
variables:
APP_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
trigger:
project: qa/e2e-suite
branch: main
strategy: depend
Variables defined on the trigger job are passed down; trigger:forward controls whether YAML and pipeline variables are forwarded. Downstream jobs can fetch upstream artifacts with needs:project or needs:pipeline:job.
30. What are CI/CD components and the CI/CD Catalog?
Answer: A CI/CD component is a reusable, versioned unit of pipeline configuration. A component project keeps its components under a templates/ directory (either templates/name.yml or templates/name/template.yml) with a README. You include a component by its full path and version:
include:
- component: $CI_SERVER_FQDN/acme/ci/secrets@1.0.0
inputs:
stage: build
Versions can be a semantic version tag, a commit SHA, a branch, or ~latest; partial versions such as 1.2 select the latest matching patch. Publishing a component project to the CI/CD Catalog uses the release keyword in a tag pipeline with semantic version tags, which makes it discoverable across the instance. Compared with plain includes, components are versioned, documented, searchable and parameterised with inputs.
31. What are spec:inputs, and how are they different from variables?
Answer: spec:inputs declares typed parameters for a configuration file or component, in a header section separated from the body by ---. Inputs are interpolated with $[[ inputs.name ]] when the configuration is composed, before the pipeline is created. Variables are resolved at runtime inside jobs.
spec:
inputs:
stage:
default: test
environment:
options: [staging, production]
---
deploy-$[[ inputs.environment ]]:
stage: $[[ inputs.stage ]]
script: ./deploy.sh $[[ inputs.environment ]]
Because inputs are validated at composition time (types, defaults, allowed options), a typo fails fast at pipeline creation instead of producing a job that silently uses an empty variable. Inputs can also shape structure, such as job names and stages, which variables cannot.
32. How do merge trains work, and what happens when one merge request fails?
Answer: A merge train queues merge requests targeting the same branch. Each pipeline tests its merge request combined with every merge request ahead of it: pipeline 1 tests A, pipeline 2 tests A+B, pipeline 3 tests A+B+C, all running in parallel. When a pipeline passes and the ones ahead have merged, its merge request merges. If B fails, B is removed from the train, C's pipeline is cancelled and restarted as A+C, and A continues. There is a limit on how many train pipelines run in parallel (twenty by default per the docs); beyond that, merge requests wait.
target branch (main)
|
[A]----+ pipeline 1: main + A
[B]----+ pipeline 2: main + A + B
[C]----+ pipeline 3: main + A + B + C
B fails -> B removed, C restarts as main + A + C
Prerequisites are merge request pipelines and merged results pipelines; merge trains are tier-dependent. "Merge immediately" bypasses the train but cancels and restarts every train pipeline, so use it sparingly.
33. How do you autoscale runners?
Answer: Three common patterns:
- Kubernetes executor, often installed with the GitLab Runner Helm chart or Operator: each job becomes a pod, and the cluster autoscaler (or Karpenter on EKS) adds nodes. Set CPU and memory requests per job so scheduling is predictable.
- Docker Autoscaler or Instance executor with a fleeting plugin for AWS, Google Cloud or Azure: the runner manager creates and removes VMs from an autoscaling group based on demand, with idle capacity settings to keep a warm pool during working hours.
- Docker Machine based autoscaling: deprecated, so plan migration to the options above.
Production consideration: Use spot or preemptible capacity for interruptible test jobs, on-demand capacity for deploy jobs, separate runner pools for trusted and untrusted workloads, and the concurrent and per-runner limit settings in config.toml to stop one team draining the fleet.
34. What changed in runner registration?
Answer: The legacy workflow used a shared registration token: anyone holding it could register a runner and choose its tags and settings on the command line. In the new workflow you create the runner in the GitLab UI or API first (choosing scope, tags, protected and untagged settings), and GitLab issues a runner authentication token with the glrt- prefix. The host registers with only that token:
gitlab-runner register --non-interactive \
--url "https://gitlab.com/" \
--token "$RUNNER_AUTH_TOKEN" \
--executor "docker" \
--docker-image "alpine:latest"
Since GitLab 17.0, instance administrators and group owners can disable the legacy registration workflow, and on GitLab.com it may need explicit re-enabling in top-level group settings. Automation such as Terraform or Helm should create runners through the API and store the glrt- token in a secret manager.
35. How do you secure runners?
Answer:
- Mark runners that hold deployment credentials or network access to production as protected, so only jobs from protected branches and tags can use them.
- Separate pools: untrusted merge request and fork jobs never share hosts with deploy jobs. Ephemeral, one-job-per-VM or per-pod execution avoids state leaking between jobs.
- Avoid privileged containers except on an isolated build pool; prefer daemonless builders.
- Give runner hosts least-privilege cloud roles, ideally none, and let jobs obtain short-lived credentials through OIDC (Q36).
- Restrict the
CI_JOB_TOKENby keeping the job token allowlist tight, so other projects cannot use a job token to reach yours. - Keep runners patched and monitor the runner fleet for offline or stale runners.
The DevSecOps interview questions guide covers supply-chain controls in more depth.
36. How do you authenticate GitLab jobs to AWS, Azure or Google Cloud without static keys?
Answer: Use ID tokens. A job declares id_tokens with an audience; GitLab mints a short-lived OIDC JSON Web Token with claims such as project path, ref, ref type and environment. The cloud provider trusts GitLab as an identity provider and exchanges the token for temporary credentials. GitLab documents this for AWS, Azure and Google Cloud, and the older CI_JOB_JWT variables are deprecated in favour of id_tokens.
deploy_aws:
image:
name: amazon/aws-cli:latest
entrypoint: [""]
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.example.com
variables:
AWS_ROLE_ARN: $PROD_DEPLOY_ROLE_ARN
AWS_ROLE_SESSION_NAME: gl-$CI_PIPELINE_ID
script:
- echo "$GITLAB_OIDC_TOKEN" > /tmp/oidc
- export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/oidc
- aws sts get-caller-identity
environment: production
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
The AWS CLI sees AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE and calls AssumeRoleWithWebIdentity itself; GitLab's own example calls aws sts assume-role-with-web-identity explicitly, and both work. The security lives in the cloud-side trust policy: condition on the sub claim, whose default format is project_path:group/project:ref_type:branch:ref:main, so only the main branch of one project can assume the production role. A trust policy that only checks the audience lets any project on the instance in. For more AWS-side detail, see the AWS interview questions guide.
37. How do you use an external secrets manager with GitLab CI/CD?
Answer: The secrets keyword fetches secrets at job start from HashiCorp Vault, Google Cloud Secret Manager, Azure Key Vault or AWS Secrets Manager, authenticating with an ID token. These integrations are tier-dependent, so check your tier; on any tier you can call the provider's CLI yourself with an ID token.
migrate_db:
id_tokens:
VAULT_ID_TOKEN:
aud: https://vault.example.com
secrets:
DATABASE_PASSWORD:
vault: production/db/password@ops
token: $VAULT_ID_TOKEN
script: ./migrate.sh
By default the secret is delivered as a file-type variable. The benefits over CI/CD variables are central rotation, audit logs in the secret manager, and short-lived dynamic credentials (for example, database users created per job).
38. How do you control who can deploy to production?
Answer: Layer the controls:
- Protected branches and tags decide who can push or merge to the refs that deploy.
- Protected environments list who is allowed to deploy to
production; others cannot run the job even if the pipeline exists. They can also require deployment approvals before the job proceeds. These are tier-dependent, so check your tier. - Environment-scoped, protected variables mean production credentials only reach jobs targeting production on protected refs.
- Protected runners with production network access only accept jobs from protected refs.
resource_groupand "prevent outdated deployment jobs" stop concurrent or backward deploys.
Real-world example: Consider an insurer whose change board requires two approvals for production. Rather than a ticket process outside the tool, a protected environment with required approvals records who approved which deployment, which an auditor can review in GitLab.
39. How do you design GitLab CI/CD for a monorepo?
Answer: The goals are to build only what changed, keep each service's pipeline readable, and still run integration tests when shared code changes.
- One small root
.gitlab-ci.ymlthat triggers a child pipeline per service withrules:changeson that service's path (plus shared library paths). - Per-service configuration files, or a dynamic child pipeline generated from a dependency graph for large repositories.
- Components for the common build, test and deploy logic so services do not copy-paste.
compare_topointing at the default branch so new branches do not rebuild everything.- Cache keys per service (
cache:key:fileson each lockfile) so services do not overwrite each other's cache. - A scheduled full pipeline on the default branch as a safety net for anything the change detection misses.
payments:
trigger:
include: services/payments/.gitlab-ci.yml
strategy: depend
rules:
- changes:
paths:
- services/payments/**/*
- libs/common/**/*
compare_to: refs/heads/main
40. How does GitLab deploy to Kubernetes today?
Answer: Through the GitLab agent for Kubernetes. A cluster-side component (agentk) opens an outbound connection to GitLab's agent server (KAS), so the cluster does not need an inbound endpoint. The older certificate-based cluster integration has been superseded by the agent.
Two workflows: the GitOps workflow, which GitLab recommends with Flux pulling manifests from Git into the cluster; and the CI/CD workflow, where the agent shares a Kubernetes context with selected projects and jobs run kubectl or helm against it. GitLab's documentation notes that the CI/CD workflow has a weaker security model and advises against it for production deployments. A practical design is CI builds, tests, scans and pushes an image, then updates a manifest repository; Flux (or Argo CD, if that is your standard) reconciles it. The GitOps interview questions and Kubernetes interview questions guides go deeper on the cluster side.
41. How do you enforce mandatory pipeline steps across hundreds of projects?
Answer: Encouragement through shared components is not enforcement: a project can simply remove the include. For enforcement, GitLab offers security policies: scan execution policies force security scans, and pipeline execution policies inject required jobs into every pipeline in the projects a policy targets. The older "compliance pipelines" feature was deprecated in GitLab 17.3 with pipeline execution policies as the replacement. These are tier-dependent, so check your tier.
Combine them with compliance frameworks (labels that mark which projects are regulated), protected branches with required approvals, and audit events.
42. What are the main levers for pipeline speed?
Answer: Measure first: open the pipeline, find the critical path, and look at queue time as well as run time. Then:
- Structure:
needsto remove unnecessary stage waits; child pipelines andrules:changesto skip unaffected work. - Parallelism:
parallelfor test splitting,parallel:matrixfor combinations. - Caching: correct cache keys,
policy: pullfor consumers, a distributed cache for autoscaled runners, and container image layer caching. - Images: prebuilt job images with tools installed instead of
apt-get installin every job; images pulled from a nearby registry or proxy. - Artifacts: small artifacts,
dependencies: []orneeds:artifacts: falsewhere downloads are not needed. - Waste:
interruptibleplus auto-cancel,on_job_failure: all, and fail-fast ordering (lint and unit tests before slow suites). - Capacity: enough runners with the right tags; queue time is a capacity problem, not a YAML problem.
Security scanning in GitLab pipelines
43. How do you add SAST, dependency scanning, secret detection and container scanning?
Answer: Include GitLab's templates (or the equivalent CI/CD components) and the jobs are added to the test stage by default:
include:
- template: Jobs/SAST.gitlab-ci.yml
- template: Jobs/Secret-Detection.gitlab-ci.yml
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
- template: Jobs/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
Points worth knowing for 2026: SAST runs open-source analyzers (Semgrep-based for many languages) on all tiers, while GitLab Advanced SAST, merge request security widgets and vulnerability management are Ultimate features. Dependency scanning has moved to an SBOM-based approach, and the older Gemnasium-based analyzer is deprecated. Container scanning uses Trivy and scans the image named in CS_IMAGE. Older guides mention a License-Scanning template; license compliance now works from dependency scanning SBOM data. Tier availability differs per scanner and feature, so check your tier rather than assuming.
Interview tip: Say how you would handle findings, not just how you enable scanners: who triages, which severities block merges (through merge request approval policies), and how false positives are dismissed with a reason.
44. What is the difference between secret push protection and pipeline secret detection?
Answer: Pipeline secret detection is a CI job that scans the repository content and reports secrets after they have been committed and pushed. Secret push protection scans commits at push time and blocks the push if it finds a known secret pattern, so the secret never reaches the remote repository (developers can skip it deliberately, which is audited). There is also client-side secret detection for issue and merge request descriptions and comments.
Push protection is prevention; pipeline detection is a safety net and also covers history. Either way, once a secret has been pushed, treat it as compromised: rotate it first, then clean up. Check your tier for push protection.
GitLab vs GitHub Actions vs Jenkins, and AI in GitLab CI/CD
45. How does GitLab CI/CD compare with GitHub Actions and Jenkins?
Answer:
| Aspect | GitLab CI/CD | GitHub Actions | Jenkins |
|---|---|---|---|
| Config | .gitlab-ci.yml, one pipeline file plus includes | Multiple workflow files in .github/workflows/ | Jenkinsfile (Groovy-based pipeline DSL) |
| Reuse | CI/CD components and Catalog, include, extends | Marketplace actions, reusable workflows | Shared libraries, plugins |
| Execution | GitLab-hosted or self-managed runners | GitHub-hosted or self-hosted runners | Controller plus agents you operate |
| Platform scope | Repo, CI/CD, registry, environments, security in one product | Tightly integrated with GitHub; security features vary by plan | CI/CD engine only; integrate everything else |
| Strengths | Merge trains, environments, built-in DevSecOps, self-managed option | Huge action ecosystem, event-driven workflows | Flexibility, long enterprise history |
| Costs to watch | Tier-gated features | Third-party action supply-chain risk | Plugin maintenance, controller upkeep |
Pick based on where the code lives, what the organisation already operates, and compliance needs, not on syntax preference. The concepts transfer: if you know GitLab well, the GitHub Actions interview questions guide maps most of them, and many Indian enterprises and GCCs still run Jenkins, which the Jenkins CI/CD course covers.
Preparing for a DevOps role where GitLab is the main toolchain? Cloudsoft's DevOps training in Hyderabad builds real pipelines with runners, containers, Kubernetes and cloud deployments, in Ameerpet or live online.
46. What does GitLab Duo add to CI/CD work, and how would you govern it?
Answer: GitLab Duo is GitLab's set of AI features. For CI/CD the relevant ones are Root Cause Analysis, which explains why a CI/CD job failed from its log and suggests a fix; GitLab Duo Chat, which can explain or draft .gitlab-ci.yml; and the GitLab Duo Agent Platform, which includes agentic chat, specialised agents (including a CI-focused agent), an AI Catalog, and flows such as the Fix CI/CD Pipeline flow and the Convert to GitLab CI/CD flow for migrating pipelines from other tools. Security-side features include vulnerability explanation and resolution. Availability depends on your subscription and add-ons, and names change, so check the current GitLab Duo documentation.
Governance is what interviewers want to hear: AI-suggested pipeline changes go through the same merge request review and pipeline as human changes; agents get least-privilege access and no route to production credentials; prompts may include job logs, so make sure logs do not contain secrets in the first place; and you measure whether it actually reduces time to fix failed pipelines. The AI coding assistants in the enterprise article covers the wider policy questions.
47. How would you build a GitLab pipeline for an AI or LLM application?
Answer: The usual stages still apply, with additions:
- Evaluation as a test stage: run a fixed evaluation set against the prompt, retrieval and model configuration, publish scores as artifacts, and fail the merge request if quality drops below an agreed threshold.
- Prompt and config versioning: prompts and model settings live in Git and change through merge requests, so every deployment is traceable.
- Cost and rate limits: evaluation jobs call paid model APIs, so run the full suite on merge requests that touch AI code (
rules:changes) and a smaller smoke set elsewhere. - Credentials: model provider keys through OIDC or a secret manager, never plain variables.
- GPU or large-memory runners: tag-selected runner pools for embedding or fine-tuning jobs, with large artifacts kept in object storage rather than CI artifacts.
- Progressive delivery: canary releases with monitoring on latency, error rate and answer quality.
The CI/CD for AI applications article details these stages.
GitLab CI/CD scenario based questions
48. A job has been stuck in "pending" for 30 minutes. How do you troubleshoot it?
Answer: Pending means no runner has picked up the job. Either no available runner matches it, or every matching runner is busy. The job page usually says which, for example "This job is stuck because you don't have any active runners that can run this job" or that it is waiting for a runner with specific tags.
What I would check:
- The job's
tagsagainst the tags on available runners. A typo such asdokceror a missing tag is the most common cause. - Whether the matching runners are online in the project's CI/CD runner settings, and whether instance or group runners are enabled for this project.
- Whether the job is untagged but all runners are set not to pick up untagged jobs.
- Whether the job runs on an unprotected branch while the only matching runner is protected.
- Capacity: runner
concurrentandlimitsettings, autoscaler maximums, cloud quotas, or Kubernetes pods stuck unschedulable for lack of CPU or memory. - On GitLab.com, whether compute minutes or quota for the namespace are exhausted.
- Runner manager logs for authentication errors, for example after a runner token was reset.
Production consideration: Alert on queue time per runner tag, not just job failures. Pending jobs are silent; developers simply wait.
49. The dependency cache is never restored, and every job downloads everything again. Why?
Answer: The cache is an optimisation, not a promise, and it is local to a runner unless a distributed cache is configured. The usual causes are different runners, a key that changes every pipeline, wrong paths, or branch protection separating caches.
What I would check:
- The job log: "Checking cache for KEY... No URL provided, cache will not be downloaded from shared cache server" or "not found" tells you whether the problem is storage or key.
- Autoscaled or Kubernetes runners without a distributed (S3-compatible) cache: each new VM or pod starts empty. Configure
[runners.cache]with object storage. - A key that includes
$CI_PIPELINE_IDor$CI_COMMIT_SHAand therefore never repeats. Usecache:key:fileson the lockfile. - Paths outside the project directory (such as
~/.m2) that cannot be cached; redirect tools to a path inside the build directory. - Protected and unprotected branches keep separate caches by default, so a feature branch will not get the main branch's cache unless you change that setting or use
fallback_keys. - Two jobs with the same key but different paths overwriting each other.
policy: pullon every job, so nothing ever uploads the cache.
Production consideration: Measure the gain. A large cache that takes longer to download and extract than the dependencies themselves is worse than no cache.
50. A developer notices a production API key printed in a job log. What do you do?
Answer: Treat the key as compromised. Contain first, then investigate, then fix the cause.
What I would check:
- Rotate or revoke the key at the provider immediately; deleting the log does not undo exposure.
- Erase the job log and artifacts (job erase in the UI or API), and check whether artifacts or downloaded logs contain the value.
- Review the provider's access logs for use of the key during the exposure window.
- Find why it was not masked: the variable was not masked, it did not meet masking requirements, or the script transformed it (base64, URL-encoding,
set -xechoing a derived string, a tool printing its config). - Check who could read the log: job logs on public or internal projects may be visible to more people than you expect.
- Check whether the variable was protected and environment-scoped; if a feature branch job could read it, that is the bigger flaw.
Production consideration: The long-term fix is to remove long-lived keys: OIDC to the cloud provider, a secret manager through the secrets keyword, masked and hidden variables for what remains, and no set -x in jobs that handle secrets.
51. The merge request pipeline takes 40 minutes. How do you bring it down?
Answer: Find where the time goes before changing anything: queue time, image pulls, dependency installs, the critical path through stages, and the slowest test jobs.
What I would check:
- Queue versus run time per job. If jobs wait ten minutes for a runner, add capacity or fix tags first.
- Stage waits: add
needsso tests start when their build finishes, andneeds: []for lint and static checks. - Dependency install time: proper cache keys, a distributed cache, a prebuilt image with toolchains baked in.
- Test suite: split with
parallel, run slow end-to-end suites only on merge trains, the default branch or a schedule, and quarantine flaky tests. - Docker builds: enable layer caching (registry cache with BuildKit) and order Dockerfile layers so dependencies are cached.
- Monorepo waste:
rules:changeswithcompare_toand per-service child pipelines. - Artifacts: stop downloading large artifacts in jobs that do not need them.
- Redundant runs:
interruptibleplus auto-cancel, and remove duplicate branch plus merge request pipelines.
Production consideration: Agree a feedback-time target and track pipeline duration over time; speed regressions creep in gradually.
52. Merge requests keep getting dropped from the merge train. What is going on?
Answer: A merge request leaves the train when its pipeline fails, when it can no longer be merged (conflicts, new commits, lost approvals), or when someone uses "merge immediately" and restarts the train. Frequent failures often mean the train is surfacing real integration breakage, or flaky tests.
What I would check:
- The system notes on the merge request, which say why it was removed.
- Whether the same tests fail across different merge requests: that points to flaky tests or shared environment state, not the code.
- Whether the failure only appears in the combined result (A+B), which is a genuine semantic conflict the train is designed to catch.
- Whether jobs in train pipelines share a mutable resource, for example one test database or a fixed review app name, so parallel train pipelines interfere.
- Whether people use "merge immediately", cancelling and restarting all train pipelines.
- Whether the train pipeline runs jobs the merge request pipeline did not, due to
ruleson$CI_MERGE_REQUEST_EVENT_TYPE, so failures appear late.
Production consideration: Each failure restarts the pipelines behind it, so a flaky suite multiplies runner cost. Fix or quarantine flaky tests before enabling merge trains on a busy repository.
53. Jobs on a self-managed runner fail with "no space left on device". How do you fix it?
Answer: Docker executors accumulate images, stopped containers, cache volumes and build cache. Docker-in-Docker builds and large artifacts make it worse.
What I would check:
df -handdocker system dfon the host to see whether images, volumes or build cache dominate.- Clean up safely: remove unused images and volumes on a schedule, or use GitLab Runner's documented cleanup tooling for Docker cache volumes; do not delete volumes of running jobs.
- Whether jobs write large files outside the build directory or keep logs that grow without limit.
- Whether
pull_policypulls fresh tags repeatedly, piling up image versions. - On Kubernetes runners: node ephemeral storage, and pod ephemeral-storage requests and limits.
- Whether the root volume is simply too small for the image sizes in use.
Production consideration: Prefer ephemeral runners (a new VM or pod per job through Docker Autoscaler, Instance or Kubernetes executors), so disk never accumulates, and alert on disk usage for any long-lived runner.
54. A deploy job meant for staging deployed to production. How did it happen, and how do you prevent it?
Answer: Typically a variable decided the target and resolved to the wrong value, or a credential with production access was available to a job that should only have had staging access.
What I would check:
- The job's resolved variables: a project-level
KUBE_CONTEXTorDEPLOY_ENVwithout environment scope overriding the YAML value (settings variables take precedence over YAML). - Environment-scoped variables: a staging job referencing
environment: productionby copy-paste, or a wildcard scope (*) on a production credential. - Shared templates or
extendschains where a job inherited the wrong environment. - Rules that let a branch pipeline run a job intended only for tags.
- Whether the staging runner or Kubernetes context also had production cluster access.
Production consideration: Make the wrong deploy impossible, not just unlikely: separate production credentials scoped only to the production environment and protected refs, a protected environment with an allowed-deployers list or approval, separate cloud accounts or clusters with OIDC trust policies that check the environment claim, and resource_group on production.
55. Every push creates two pipelines. Why, and how do you fix it?
Answer: Some jobs have rules matching merge request events and others (or the same ones) match branch pushes, so a push to a branch with an open merge request creates a branch pipeline and a merge request pipeline.
What I would check:
- The pipeline list: one has the "merge request" label, the other is a branch pipeline for the same commit.
- Jobs with rules ending in a bare
- when: on_successorif: $CI_COMMIT_BRANCHcombined with merge request rules. - Included templates that add their own rules for both pipeline types.
Fix it with workflow:rules as in Q12, so the branch pipeline is suppressed when a merge request is open.
Production consideration: Duplicates double runner cost. Encode one pipeline strategy in a shared workflow component.
56. A job that should run on merge requests never appears in the pipeline. How do you debug it?
Answer: A missing job is a rules problem: no rule matched, an earlier rule matched with when: never, or workflow:rules created a different pipeline type than you expected.
What I would check:
- The merged configuration in the pipeline editor, which shows the job's actual rules after includes and
extends. - The pipeline type: if it is a branch pipeline, rules on
merge_request_eventnever match. - Rule order: an earlier broad
when: neverrule wins because the first match decides. rules:changespaths, glob syntax and the comparison base.- Variable expressions: quoting, comparing
$CI_COMMIT_BRANCHin a merge request pipeline (where it is not set; use$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME). - A
needsreference to a job that was excluded, which causes a pipeline creation error unlessneeds:optionalis used.
Production consideration: Keep a few shared, named rule templates reused with !reference, so rule logic stays consistent.
57. Your team is migrating 200 Jenkins pipelines to GitLab CI/CD. How do you approach it?
Answer: Treat it as a platform project, not 200 manual rewrites.
What I would check:
- Inventory: group Jenkinsfiles into patterns (Java Maven service, Node front end, Terraform module) and note shared libraries, plugins and credentials used.
- Build GitLab CI/CD components for each pattern, with inputs replacing Jenkins parameters, and publish them to the catalog.
- Map concepts: Jenkins agents to runner tags, credentials to protected variables or OIDC, stages to stages or
needs,inputsteps to manual jobs or protected environment approvals, shared libraries to components. - Migrate a pilot service per pattern, run both systems in parallel briefly, and compare results and duration.
- Use AI assistance, such as GitLab Duo's Convert to GitLab CI/CD flow where available, to produce first drafts, then review them like any other change.
- Decommission Jenkins jobs only after the GitLab pipeline has handled real releases.
Production consideration: Credentials are the riskiest part. Use the migration to remove long-lived cloud keys rather than copying them into GitLab variables. Engineers moving between the two tools benefit from knowing both; the DevOps engineer interview questions guide covers the broader CI/CD design questions.
58. An OIDC-based deploy to AWS fails with "Not authorized to perform sts:AssumeRoleWithWebIdentity". What do you check?
Answer: The token was issued, but AWS rejected it against the role's trust policy, or the identity provider configuration does not match.
What I would check:
- The IAM OIDC identity provider URL matches the GitLab instance address exactly (for example
https://gitlab.com). - The
audinid_tokensmatches the audience configured on the identity provider and in the trust policy. - The trust policy's
subcondition matches this pipeline: project path,ref_typeand ref. A tag pipeline does not match a condition written forref_type:branch:ref:main. - Whether the condition uses
StringEqualswhere a wildcard needsStringLike. - Whether the job uses a deprecated
CI_JOB_JWTvariable rather than theid_tokensvariable. - For self-managed GitLab, whether AWS can reach the instance's OIDC discovery endpoint.
Production consideration: Keep trust policies narrow (one project, protected refs, ideally the environment claim) and separate roles for staging and production.
59. A flaky test fails one pipeline in five and blocks merges. What do you do?
Answer: Stop the bleeding without hiding the problem. Blanket retries make flaky tests permanent.
What I would check:
- The JUnit reports across pipelines to identify which tests fail intermittently and on which runners.
- Whether failures correlate with a runner pool (resource starvation), time of day (shared environment load) or parallel jobs sharing state.
- Test dependencies on ordering, real time, network calls or shared databases.
- Short term:
retrylimited to infrastructure failures (retry: { max: 2, when: [runner_system_failure, stuck_or_timeout_failure] }), notscript_failure; quarantine the specific flaky tests into a non-blocking job with an owner and a ticket. - Long term: fix the test, isolate state per job (unique database schema per pipeline), and track the flaky-test count.
Production consideration: Flakiness hurts merge trains most, because each failure restarts the pipelines behind it.
60. A deploy job fails because the artifact from the build job is missing. Why?
Answer: Either the artifact was never uploaded, it expired, or the deploy job was told not to download it.
What I would check:
- The build job log: "Uploading artifacts... WARNING: dist/: no matching files" means the path is wrong or relative to the wrong directory.
expire_in: a manual production deploy run days later finds expired artifacts (the latest artifacts on a ref may be kept, depending on settings, but do not rely on it for older pipelines).needsordependencies:dependencies: [],needs:artifacts: false, or aneedslist that does not include the build job.- Same-stage jobs: artifacts from a job in the same stage are only fetched through
needs. - Cross-pipeline use: a deploy in a downstream pipeline needs
needs:pipeline:joborneeds:project, not a plain job name. - Artifact size limits, which cause upload failures on large builds.
Production consideration: For deployable outputs, push a versioned package or container image to a registry and deploy from that, rather than relying on CI artifacts. It gives you immutable, traceable releases and rollbacks that do not depend on artifact retention.
Key takeaways
- Use
rulesandworkflow:rules;only/exceptare deprecated, and the first matching rule decides. - Cache is an optional speed-up for dependencies; artifacts are reliable hand-offs between jobs. Never pass build outputs through cache.
needs, child pipelines,rules:changesand correct caching are the main speed levers; queue time is a capacity problem.- CI/CD components with
spec:inputsand the CI/CD Catalog are the modern way to share pipeline logic; pin versions. - Production safety comes from layers: protected branches, protected environments, scoped protected variables, protected runners and
resource_group. - Replace static cloud keys with
id_tokensand narrow trust policies; masking is not a security boundary. - Many features are tier-dependent; in interviews, say "check your tier" rather than guessing.
Interview preparation checklist
- Write a
.gitlab-ci.ymlfrom memory with stages,needs, cache, artifacts, rules and a manual production deploy. - Explain merge request, merged results and merge train pipelines, and the
workflow:rulesduplicate-pipeline fix. - Register a runner with the new
glrt-token workflow on a VM or Kubernetes, and break it deliberately (wrong tags, protected runner) to see "pending". - Build and publish one CI/CD component with inputs, and consume it from another project with a pinned version.
- Set up OIDC from a GitLab job to one cloud provider and write the trust policy condition on
sub. - Add SAST, secret detection, dependency and container scanning templates and explain how findings would be triaged.
- Deploy a review app with
on_stopandauto_stop_in, and a production deploy with a protected environment. - Prepare two stories from your own work: a pipeline you made faster (with before and after numbers you measured) and a failure you debugged.
- Be ready to compare GitLab with GitHub Actions and Jenkins without bias.
FAQ
What skills are needed for a GitLab CI/CD role?
Git, Linux and shell scripting, YAML, Docker, one cloud platform, Kubernetes basics, and a solid grasp of GitLab pipelines, runners, rules, variables, environments and security scanning. Troubleshooting skill matters as much as syntax.
How should I prepare for a GitLab CI/CD interview?
Build a real project on GitLab with a multi-stage pipeline, a self-managed runner, a container build, a Kubernetes or cloud deploy and security scans. Break it on purpose and practise explaining how you diagnosed each failure.
Is GitLab CI/CD asked in DevOps interviews for freshers?
Often, when the company uses GitLab. Freshers are usually asked about pipelines, stages, jobs, runners, artifacts versus cache, variables and a simple .gitlab-ci.yml, plus Git basics.
Is GitLab CI/CD free to use?
GitLab offers a free tier that includes core CI/CD pipelines and runners, while features such as merge trains, protected environments and some security capabilities need paid tiers. Check GitLab's current plans before designing around a feature.
Should I learn GitLab CI/CD, GitHub Actions or Jenkins first?
Learn the one your target employers use, then the concepts transfer. Pipelines, runners, caching, artifacts, secrets and environments work similarly across all three, and many enterprises still run Jenkins alongside newer tools.
Do I need Kubernetes knowledge for GitLab CI/CD interviews?
For most mid-level roles, yes. Expect questions on deploying to Kubernetes, the GitLab agent for Kubernetes, runners on Kubernetes and GitOps with Flux or Argo CD.
Are GitLab certifications useful?
They can help with shortlisting, but interviewers care more about whether you can design and troubleshoot pipelines. Pair any certification with a project you can explain in depth.
How is AI changing GitLab CI/CD work?
AI features such as GitLab Duo can explain failed jobs, draft pipeline configuration and assist with migrations. Engineers still own reviewing those changes, securing pipelines and deciding what is safe to deploy.
What experience do interviewers expect for senior GitLab roles?
Designing shared CI/CD components, running runner fleets, securing deployments with protected environments and OIDC, enforcing policies across many projects, and measurably improving pipeline speed and reliability.
If you want hands-on practice with GitLab pipelines, runners, Docker, Kubernetes, Terraform and cloud deployments, explore Cloudsoft's DevOps course in Ameerpet and online; for a broader path that also covers AI, ML and cyber security, look at the APEX AI, ML, Cloud and Cyber Security program. Call +91 96660 19191 to book a free demo.



