All GitLab exams
Free GitLab Certified CI/CD Associate practice test: 30 questions with answers
30 original questions for GitLab Certified CI/CD Associate, drawn from every topic area. Answer each one to see whether you got it right and why. No sign-up.
- Free questions
- 30
- Full bank
- 112 questions
- Real exam
- 50 questions, 75 min
- Passing score
- 75%
GitLab Certified CI/CD Associate exam guide: topics, cost and format
All 30 GitLab Certified CI/CD Associate questions with answers
The same questions as the test above, grouped by exam topic. Open any question to see the answer and explanation.
YAML Configuration (5 questions)
Question 1
A job has two entries in its `rules:` list. The first entry is `if: $CI_PIPELINE_SOURCE == 'schedule'` with `when: never`. The second entry is `if: $CI_COMMIT_BRANCH` with no `when` key. A scheduled pipeline starts on the main branch. What happens to the job?
- AIt is added to the pipeline and runs, because the second rule matches the branch name
- BIt is added as a manual job, because a rule without a when key makes the job wait for approval
- CIt is not added to the pipeline, because the first matching rule sets when: never
- DIt is added and runs, but allow_failure is set to true automatically for scheduled pipelines
Show answer and explanationHide answer
Correct answer: CRules are read from top to bottom and the first rule that matches decides the outcome. The schedule matches the first rule, which sets when: never, so the job is dropped and the second rule is never reached. A rule without a when key does not make a job manual, and scheduled pipelines do not change allow_failure on their own.
Question 2
A team wants a job definition kept in `.gitlab-ci.yml` as a reusable base that never runs by itself, while other jobs inherit from it with `extends`. Which naming convention achieves this?
- APrefix the job name with an underscore, such as _deploy_base
- BAdd the key `template: true` to the body of the job definition
- CPrefix the job name with a period, such as .deploy_base
- DMove the job under a top-level key called templates in the same file
Show answer and explanationHide answer
Correct answer: CJob names that begin with a period are hidden jobs, so GitLab never runs them, while extends and !reference can still read them. An underscore has no special meaning in CI/CD, and template: true and a templates key are not recognised keywords.
Question 3
Which two statements about `artifacts` and `cache` are correct? (Choose two.)
- AArtifacts are files a job produces for later jobs in the pipeline, and they can be downloaded from the job page
- BA cache is guaranteed to exist for every job in the same pipeline, so deploy jobs can always rely on it
- CA cache holds reusable dependencies to speed up later jobs, and it may be missing on a later run
- DArtifacts are restored from the cache automatically before each job starts, so they never need a download
Show answer and explanationHide answer
Correct answer: A, CArtifacts carry job outputs to later jobs and can be downloaded, while the cache stores dependencies for speed and a cache miss is always possible. Because a cache can be missing, it should not carry build output to a deploy job, and artifacts are never restored from the cache.
Question 4
A build job compiles a program into `dist/app`. A deploy job in the next stage must use that exact file from the same pipeline. Which keyword should the build job use to make the file available?
- Acache with paths set to dist/app, so the deploy job restores the file from storage
- Bartifacts with paths set to dist/app, which passes the file to later jobs
- Cdependencies set to dist/app, which copies the file into the next job's workspace
- Dvariables with APP_PATH set to dist/app, so the deploy job reads the location
Show answer and explanationHide answer
Correct answer: BArtifacts are the mechanism for passing files produced by one job to later jobs in the same pipeline. A cache is for reusable dependencies and is not guaranteed to be present, a variable only stores text, and dependencies expects job names rather than file paths.
Question 5
A team wants Node.js dependencies reused across pipelines, and the cache should be replaced only when `package-lock.json` changes. Which configuration does this?
- Acache with key set to the pipeline ID, and paths set to node_modules/
- Bcache with key files set to package-lock.json, and paths set to node_modules/
- Cartifacts with paths set to node_modules/, so the next pipeline downloads them
- Dvariables with NODE_MODULES_PATH set to the lock file, so jobs read the lock file
Show answer and explanationHide answer
Correct answer: BA cache key built from key files changes only when the listed file changes, so the dependency cache is reused until the lock file is updated. A pipeline-ID key creates a new cache on every run, and artifacts are meant for passing outputs between jobs rather than reusing dependencies across pipelines.
Pipeline Development (5 questions)
Question 6
A deploy job sits in the deploy stage. It must start as soon as one specific build job succeeds, rather than waiting for every job in the build stage. Which keyword makes this happen?
- Aparallel, set to the number of build jobs so they all run together
- Bdependencies, listing the build job so the deploy job can download its artifacts
- Cneeds, listing the specific build job as a prerequisite of the deploy job
- Dextends, pointing at the build job so the deploy job inherits its configuration
Show answer and explanationHide answer
Correct answer: CThe needs keyword creates a dependency edge in the pipeline graph, so the deploy job starts once the listed job has succeeded. The dependencies keyword only controls which artifacts are downloaded, parallel splits a job into copies, and extends copies configuration, so none of them change when a job starts.
Question 7
A job occasionally fails because the runner host reboots in the middle of the job. The team wants one automatic retry only for that situation, and no retries when the script itself fails. Which configuration does this?
- Aretry set to 1 with no other keys, so any failure is retried once
- Btimeout set to a longer duration, so a reboot does not stop the job early
- Callow_failure set to true, so the reboot does not block the rest of the pipeline
- Dretry with max set to 1 and when set to runner_system_failure
Show answer and explanationHide answer
Correct answer: DThe retry keyword accepts a max count and a when list, and runner_system_failure matches failures caused by the runner, so script failures are not retried. A plain retry value retries every failure, a longer timeout does not recover a crashed runner, and allow_failure hides the failure rather than retrying it.
Question 8
A pipeline must build its child pipeline configuration from a file that an earlier job produced. Which two statements about parent-child pipelines are correct? (Choose two.)
- AA trigger job can include a YAML file that an earlier job saved as an artifact
- BChild pipeline jobs must be written in the same YAML file as the parent pipeline
- CSetting strategy to depend makes the trigger job reflect the result of the child pipeline
- DChild pipelines cannot define their own stages and always reuse the parent pipeline's stages
Show answer and explanationHide answer
Correct answer: A, CThe trigger keyword can include a generated configuration file from an artifact, and strategy depend makes the trigger job wait for and mirror the child pipeline's status. Child pipelines are separate pipelines with their own configuration and stages, so they are not limited to the parent's file or stage list.
Question 9
A pipeline defines the stages build, test, and deploy. A job named integration sits in the test stage and has no needs keyword. When can it start?
- AImmediately, because jobs without a needs keyword ignore stage order
- BAfter every job in the build stage has finished successfully
- CAs soon as the first job in the build stage finishes, even if others still run
- DOnly after a person approves it manually, because test stages always require approval
Show answer and explanationHide answer
Correct answer: BWithout needs, a job waits until all jobs in earlier stages have completed successfully before it starts. Stage ordering is the default behaviour, so the job does not start after only the first build job, and no approval is required.
Question 10
A team enables auto-cancel redundant pipelines for its project. What does setting `interruptible: true` on a job do?
- AIt lets a newer pipeline on the same ref cancel this job while it still runs
- BIt restarts the job automatically if the runner loses its connection
- CIt pauses the job until a user approves it in the pipeline view
- DIt lets the job fail without marking the whole pipeline as failed
Show answer and explanationHide answer
Correct answer: AWith auto-cancel redundant pipelines turned on, a newer pipeline on the same ref cancels older running pipelines, but only jobs marked interruptible: true are cancelled this way. Manual approval uses a manual job, restarts after connection loss are a retry matter, and failing without failing the pipeline is the allow_failure keyword.
CI/CD Fundamentals (4 questions)
Question 11
Which statement best distinguishes continuous delivery from continuous deployment?
- AContinuous delivery skips the automated test stage to save time, while continuous deployment always runs the full test suite before any release is made
- BContinuous delivery requires one long-lived branch for all developers, while continuous deployment forbids shared branches and needs separate repositories
- CContinuous delivery applies only to container images, while continuous deployment applies only to virtual machines and bare-metal servers in data centres
- DContinuous delivery keeps every change releasable with a manual production release, while continuous deployment releases each passing change automatically
Show answer and explanationHide answer
Correct answer: DContinuous delivery keeps the mainline releasable at all times, and a person decides when production gets the change. Continuous deployment goes one step further and releases every change that passes the pipeline without a manual gate. The other options describe skipped tests, technology limits, or branching rules that are not part of either definition.
Question 12
A team merges feature branches only at the end of each month. Every merge brings a large batch of conflicting changes and a long debugging session. Which CI practice addresses this most directly?
- ADelay code review until the monthly merge, so reviewers see all changes together
- BBuild and test only the release candidate at the end of each month, to save runner time
- CGive each developer a separate copy of the production environment for the whole month
- DIntegrate small changes into the main branch often, with automated build and tests on every merge
Show answer and explanationHide answer
Correct answer: DFrequent integration of small changes, checked automatically on each merge, keeps conflicts and surprises small and visible early. The other options either delay testing until the batch is large, multiply environments without integrating anything, or postpone review, which makes the problem worse.
Question 13
A test job needs a running PostgreSQL database during its script. The team wants the script to connect to the database using the hostname postgres. Which keyword provides this?
- Aimage set to postgres, so the job's script runs inside a database container
- Bcache listing postgres, so the database data directory is restored before the job
- Cartifacts listing postgres, so the database binary is passed into the job from earlier
- Dservices listing postgres, which starts a linked container reachable at that hostname
Show answer and explanationHide answer
Correct answer: DThe services keyword starts additional containers alongside the job container, and each one is reachable using its image name as the hostname. Setting image changes the environment the job itself runs in, while cache and artifacts only move files and cannot start a running database.
Question 14
Which practice best keeps a pipeline fast and makes failures visible early?
- ARun every test in one large job at the end, so the earlier stages stay as short as possible
- BPlace quick lint and static checks in an early stage, and use needs so later jobs start when their inputs are ready
- CSet allow_failure to true on every job, so no single job can stop the rest of the pipeline
- DRun every job on every commit, regardless of which files changed, so behaviour stays predictable
Show answer and explanationHide answer
Correct answer: BQuick checks early stop broken changes before expensive work runs, and needs lets jobs start as soon as their inputs are ready instead of waiting for whole stages. The other options hide failures, delay feedback, or waste runner time on unchanged work.
Troubleshooting and Optimization (4 questions)
Question 15
A developer pushes a feature branch, and no pipeline appears at all. The project's .gitlab-ci.yml has a workflow rules section that only allows merge request pipelines and says nothing about branch pipelines. What is the most likely explanation?
- AThe runner is offline, so the pipeline was created but never moved past the created state
- BThe workflow rules evaluate to no pipeline for a branch push, so GitLab never creates one
- CBranch pipelines always need a manual trigger in the web interface before they are created
- DThe jobs have no tags, so the pipeline stays hidden until a runner with a matching tag exists
Show answer and explanationHide answer
Correct answer: BThe workflow keyword decides whether a pipeline is created at all, and when no rule allows a branch push, no pipeline is made. An offline runner or missing tags affects jobs after a pipeline exists, and branch pipelines do not need a manual trigger by default.
Question 16
Before merging a large .gitlab-ci.yml change, a maintainer wants to confirm that the YAML is valid and see the fully merged configuration, including includes and extends. Which tool is designed for this?
- AThe job log from the previous pipeline, which prints the merged YAML for every job
- BThe CI Lint tool or the validation view in the pipeline editor
- CThe git blame view for the file, which shows who last changed each line
- DThe runner's debug flag set on a local machine, which reports YAML syntax errors
Show answer and explanationHide answer
Correct answer: BCI Lint and the pipeline editor check the syntax and show the configuration after includes and extends are resolved. Previous job logs show what ran rather than the merged configuration, git blame only shows history, and a runner debug flag reports runner activity rather than YAML validity.
Question 17
A job stays in the pending state and never starts. Which two checks help find the cause? (Choose two.)
- ACheck that a runner which is online and not paused has every tag listed in the job's tags
- BCheck that the runner's concurrency limit is not already used up by other running jobs
- CCheck that adding needs: [] to the job lets it skip the stage order and start
- DCheck that the artifacts expiry time is long enough for the job to be picked up
Show answer and explanationHide answer
Correct answer: A, BA job waits in pending until a runner accepts it, which requires an online, unpaused runner with every tag the job asks for and free concurrency slots. Changing needs or artifact expiry does not affect whether a runner can accept the job.
Question 18
A repository has a very long commit history, and every job spends several minutes cloning it before any work begins. The jobs only need the latest commit. Which variable reduces the clone time?
- AGIT_DEPTH, set to 1, which limits the clone to the most recent commit
- Binterruptible, set to true, which skips cloning of older commits automatically
- Cparallel, set to 50, which divides the clone work across more job copies
- Dexpire_in on the artifacts, set to a longer period, which keeps the clone cached
Show answer and explanationHide answer
Correct answer: AGIT_DEPTH limits how much history the runner fetches, so a value of 1 clones only the latest commit. The parallel keyword multiplies jobs, interruptible only affects cancellation, and artifact expiry governs how long uploaded files are kept.
Container and Package Management (4 questions)
Question 19
What is the main purpose of the Dependency Proxy in GitLab?
- AIt stores the images that the team's own pipelines build and push for later deployment
- BIt scans container images for known vulnerabilities before they are deployed
- CIt runs jobs on a remote runner without needing a local Docker daemon on that host
- DIt caches Docker Hub images within a group so repeated image pulls are faster and reduce outside downloads
Show answer and explanationHide answer
Correct answer: DThe Dependency Proxy keeps a local copy of upstream images such as Docker Hub images, so jobs in the group pull from GitLab and repeat downloads from the public registry are reduced. Storing team-built images is the job of the Container Registry, scanning is a separate security feature, and runner executors are configured on the runner rather than through this proxy.
Question 20
A job builds a Docker image and pushes it to the project's container registry. Which two statements are correct? (Choose two.)
- AThe predefined CI_REGISTRY_IMAGE variable gives the project's registry path to use in the image tag
- BThe predefined CI_REGISTRY_USER and CI_REGISTRY_PASSWORD variables let the job log in to the registry
- CImages pushed by a job are removed automatically when that job finishes, so they must be pushed again
- DImage tags must match the name of the job that pushed them, otherwise the push is rejected
Show answer and explanationHide answer
Correct answer: A, BCI_REGISTRY_IMAGE holds the registry path for the project, and CI_REGISTRY_USER and CI_REGISTRY_PASSWORD are predefined credentials the job can use to log in. Pushed images persist after the job ends, and tags have no required link to job names.
Question 21
A Dockerfile needs compilers and build tools to produce an application, but the final image should not contain them. The team wants to keep a single Dockerfile. Which approach fits?
- AUse a multi-stage build that copies only the compiled output into a slim final image
- BRun two separate docker push commands, one for an image with build tools and one without
- CIncrease the number of parallel jobs so the build tools are removed from the runner sooner
- DSet the job's image keyword to the largest base image available, so the tools are already present
Show answer and explanationHide answer
Correct answer: AA multi-stage Dockerfile compiles in an intermediate stage and copies only the needed output into the final stage, so build tools never reach the shipped image. Pushing two images, changing parallel job counts, or using a larger base image does not remove the tools from the final image.
Question 22
A team wants every image pushed by a pipeline to be traceable back to one specific commit. Which tag approach fits?
- AAlways tag the image latest, so the newest build is easy to find in the registry
- BTag the image with CI_COMMIT_SHORT_SHA, so each build maps to exactly one commit
- CTag the image with the runner's host name, which changes whenever a runner is reinstalled
- DTag the image with the job name only, so each new build overwrites the previous image
Show answer and explanationHide answer
Correct answer: BCI_COMMIT_SHORT_SHA is a predefined variable that holds the short commit hash, so a tag built from it points to one commit. A latest tag moves with every build, a runner host name says nothing about the code, and a job-name tag would be overwritten by each build.
Security Integration (4 questions)
Question 23
A team wants static application security testing results shown on merge requests, without writing its own scanner. Which approach fits?
- AWrite a custom shell job that searches the source tree for risky function names
- BEnable the Container Registry cleanup policy so old images are removed on a schedule
- CInclude the SAST security template in .gitlab-ci.yml so its scanner job runs and reports
- DSet allow_failure to true on every job in the pipeline so reports never block merges
Show answer and explanationHide answer
Correct answer: CIncluding the SAST template adds GitLab's maintained scanner jobs, which publish SAST reports that appear in merge requests. A text search is not full static analysis, cleanup policies handle images, and allow_failure hides results rather than producing them.
Question 24
A team's linter writes its findings to a JSON file in Code Climate format, and the team wants those findings shown in merge requests. Which job configuration does this?
- Aartifacts with reports set to codequality, pointing at the JSON file
- Bartifacts with reports set to junit, pointing at the JSON file
- Ccache with paths set to the JSON file, so the next pipeline reads it
- Ddependencies set to the JSON file, so the merge request job imports it
Show answer and explanationHide answer
Correct answer: AThe codequality report type accepts Code Climate JSON and displays the findings in merge requests. JUnit reports are XML test results, while cache and dependencies do not turn a file into a merge request report.
Question 25
A team is worried that API keys could be committed to the repository by mistake. It wants a scanner that runs in its pipeline without writing custom scripts. What should it do?
- AInclude the Secret-Detection template, which adds a scanner job that reports leaked credentials
- BMark every variable as masked, which stops secrets from ever being committed to the repository
- CSet allow_failure to true on the lint job, so secret findings never block a merge request
- DAdd a regular expression to the variables section, which blocks any push that contains a key
Show answer and explanationHide answer
Correct answer: AThe Secret Detection template is GitLab's maintained scanner for leaked credentials, and including it adds a job that reports findings. A variables regex does not scan commits, masking only hides values in job logs, and allow_failure hides findings rather than reporting them.
Question 26
A production deploy token must be available only to pipelines that run on protected branches or protected tags. Which CI/CD variable setting enforces that?
- AMark the variable as protected, so it is passed only to pipelines on protected branches or tags
- BMark the variable as masked, which hides its value from anyone who can edit project settings
- CStore the token in the Dependency Proxy settings, which limits its use to the default branch
- DSet the environment scope to an asterisk, which exposes the variable to every environment
Show answer and explanationHide answer
Correct answer: AProtected variables are passed only to pipelines running on protected branches or tags. Masking hides values from job logs rather than restricting access, the Dependency Proxy only pulls upstream images, and an asterisk scope exposes the variable more widely.
Runner Configuration (4 questions)
Question 27
A job has tags set to docker-large. The project's only available runner has the tags docker and linux, so the job stays pending. What is the most direct fix?
- AAdd interruptible: true to the job so it moves ahead of other pending jobs in the queue
- BRemove the artifacts section from the job so the runner has more disk space available
- CGive a runner the docker-large tag, or change the job to use a tag the runner already has
- DSet allow_failure to true on the job so the pipeline stops waiting for it to start
Show answer and explanationHide answer
Correct answer: CA job runs only on runners that have every tag it requests, so the tags must match on one side or the other. Interruptible, artifact settings, and allow_failure do not change which runner can accept the job.
Question 28
On a single host with Docker installed, which executor starts a new Docker container from the job's image for every job?
- AThe docker executor, which creates a new container from the job's image for each job
- BThe ssh executor, which runs job commands on a remote machine reached over an SSH connection
- CThe parallels executor, which runs each job inside a desktop virtual machine on the host
- DThe shell executor, which runs job commands directly on the runner host's operating system
Show answer and explanationHide answer
Correct answer: AThe Docker executor is the standard choice for container-per-job isolation, using the image keyword from the job definition. The shell executor has no container isolation, and the ssh and parallels executors run jobs on a remote machine or inside a virtual machine rather than a container from the job's image.
Question 29
A group has five projects, and the team wants one new runner to serve jobs from all five projects and nothing outside the group. Which runner type fits?
- AAn instance runner, which serves only the projects owned by the instance administrator
- BA runner with a group-only tag, which the platform restricts to members of that group
- CA project runner, which serves only the single project it was registered with
- DA group runner, which serves every project inside that group and no other
Show answer and explanationHide answer
Correct answer: DA group runner is registered at the group level and can run jobs for every project in that group, which fits one runner for five projects. An instance runner serves projects across the whole instance, a project runner only serves the project it was registered with, and tags do not restrict access by group membership.
Question 30
One host runs three registered runners, and the team wants to cap how many jobs that host runs at the same time across all of them. Which setting does this?
- AThe limit value on one registered runner, which caps only that runner's own jobs
- BThe concurrent value in the global section of the runner's config.toml file
- CThe tags list on each registered runner, which sets how many jobs it is allowed to accept
- DThe check_interval value, which sets how often the runner asks GitLab for new jobs
Show answer and explanationHide answer
Correct answer: BThe global concurrent setting in config.toml caps the total number of jobs the runner process runs at once across all of its registered runners on the host. A per-runner limit caps only that runner, tags decide which jobs a runner may take, and check_interval controls how often it polls for work.