How do you make sure a software change works perfectly without testing every single line of code by hand every time? The answer is automated testing and a CI/CD pipeline — a system that catches bugs early, deploys updates automatically, and saves you from the nightmare of breaking something at 2 a.m. For the PCD exam, you need to know exactly how Google Cloud Build orchestrates this process so that you can set it up reliably for any application.
Jump to a section
A simple way to picture Application Testing and CI/CD Pipelines
A restaurant kitchen is a high-stakes testing and delivery line. Every plate that leaves the pass is the final product, and mistakes cost real money and reputation. The chef de partie for each station is a developer writing code for a specific component — the grill station handles proteins, the sauce station handles reductions. Before any dish reaches a customer, it must pass a series of quality gates. The prep cook tests that the vegetables are fresh. The sous chef runs a 'taste test' — your unit test. The head chef then inspects the plated dish for colour and balance — that is the integration test. If the garnish is wrong, the plate goes back, not out. This is the automated test pipeline: each stage catches errors before the dish reaches the dining room.
The restaurant also runs a special for Friday night — a new menu item. The team agrees on the recipe (commit), then the prep team builds a small batch to check the timing (build). They run the full tasting procedure (test suite). If it passes, they stage it on the specials board for one night only (staging environment). If customers love it, it becomes a permanent menu item (production deployment). Every new special follows this exact sequence, automated as much as possible by checklists and timers. The head chef does not manually taste every batch of mashed potato — they trust the process. That trust is the CI/CD pipeline: a repeatable, auditable, and fast system for turning a recipe change into a dish on the table.
Let us start with the problem software developers faced twenty years ago. A team of five people would each write code on their own computer. When they finished a feature, they would "merge" their code — combine it with everyone else's — and then manually run a few tests. If the tests passed, they would manually copy the files to a server. This approach was slow, error-prone, and caused a famous problem called "it works on my machine." One developer's environment had a different library version, so the code broke on the server but not on their laptop. The industry realised it needed a standardised, automated process.
Continuous Integration (CI) is the practice of merging all developers' code changes into a shared main branch many times a day. Each merge triggers an automated build — the process of compiling source code into a deployable format — and a suite of automated tests. The goal is to find integration problems early, ideally within minutes of a code change. If the build or tests fail, the team is alerted immediately and can fix the issue before anyone builds more work on top of the broken code.
Continuous Delivery (CD) extends CI by automatically deploying every change that passes the CI pipeline to a staging environment — a near-exact copy of production used for final validation. A human can still decide whether to push the change to live customers. Continuous Deployment goes one step further: any change that passes all automated stages is automatically released to production with no manual button click. For the PCD exam, you need to understand the difference, but the focus is on the automated pipeline itself.
Cloud Build is Google Cloud's managed CI/CD service. It runs on Google's infrastructure, so you do not need to maintain your own build servers. You define your pipeline in a YAML file — YAML is a human-readable format for configuration data — called cloudbuild.yaml. This file tells Cloud Build: what steps to run, in what order, and what triggers should start the pipeline. Typical steps include:
- Fetching source code from a repository like GitHub or Cloud Source Repositories.
- Running tests, often using a test framework like JUnit for Java or pytest for Python.
- Building a container image using Docker — a way to package code with all its dependencies into a single, portable unit.
- Pushing the container image to Artifact Registry, Google Cloud's container image storage.
- Deploying the image to a target environment like Google Kubernetes Engine (GKE) or Cloud Run.
Cloud Build can be triggered automatically by events — for example, a push to a specific branch in your repository, or a new tag being created. You can also run builds manually or on a schedule. The service supports parallel steps (multiple tasks running at the same time) and conditional steps (run this step only if a previous step succeeded).
Automated testing is the backbone of a reliable CI/CD pipeline. Tests are code that checks your code. The main types you will see on the exam are: - Unit tests: test a single function or method in isolation. They are fast and run first. - Integration tests: test how different parts of the system work together, such as a service calling a database. - End-to-end tests: test the entire application flow from the user interface to the backend, simulating real user behaviour.
Cloud Build can run all these tests inside build steps. You define custom build steps by specifying a container image for each step — for example, a step using the node:14 image to run npm test. The exam expects you to know how to configure these steps, including setting environment variables, using secrets for API keys, and specifying timeouts so that builds do not run forever.
Why does this matter for the PCD exam? Google asks you to design, implement, and troubleshoot CI/CD pipelines using Cloud Build. You need to understand the YAML syntax, the available builders (like gcloud, docker, and custom images), and how to integrate with other Google Cloud services like Cloud Storage for build artifacts and Cloud Logging for build logs. You will also see questions about triggers — the conditions that start a build — and about service accounts — the identity that Cloud Build uses to access other Google Cloud resources.
Write the cloudbuild.yaml file
Create a YAML file in the root of your repository that defines each build step. Each step specifies a container image to run, the command to execute, and dependencies on other steps. This file is the blueprint for your whole pipeline.
Connect your source repository
In the Google Cloud Console, go to Cloud Build and connect your repository provider (GitHub, Bitbucket, or Cloud Source Repositories). This creates a webhook so that Cloud Build knows when a new commit or pull request happens.
Create a build trigger
Define when the pipeline should run — for example, on every push to the `main` branch, or only when a tag matching `v*` is created. You can also set substitution variables here, like `_REGION=us-east1`, to customise the build for different environments.
Run automated tests
Inside one of the build steps, execute your test suite. For example, use `mvn test` for Java or `npm test` for Node.js. If any test fails, the step returns a non-zero exit code and the entire build fails, preventing bad code from going further.
Build and push the artifact
After tests pass, compile your code and package it into a container image (or a JAR, ZIP, etc.). Push the image to Artifact Registry, tagging it with the commit hash or a version number so you can trace which code generated each deployment.
Deploy to the target environment
In the final step, use a step that runs the `gcloud` command to deploy the image to Cloud Run, GKE, Compute Engine, or another service. For production, this step might require manual approval, which you can set up using a separate trigger or a Cloud Build approval mechanism.
A mid-sized e-commerce company called "ShopWell" sells organic groceries online. Their development team of twelve engineers works on a monolithic Java application — a single large codebase that runs everything from the shopping cart to the payment processing. Every week they release a new version by manually copying WAR files to a server. Last month, a developer pushed a change that broke the checkout flow. Because they only tested manually on Friday afternoon, the bug reached customers on Saturday morning. The company lost £40,000 in sales and upset hundreds of customers.
The CTO decides to implement a CI/CD pipeline using Cloud Build. Here is how the senior DevOps engineer sets it up step by step.
First, the team moves their code from a disorganised folder on a shared drive to a GitHub repository. They create a branching strategy: developers work in feature branches, and when they finish a feature, they create a pull request (PR) to merge into the develop branch. Every PR triggers a webhook — an HTTP callback — that Cloud Build receives. The engineer creates a cloudbuild.yaml file in the root of the repository.
The pipeline has six steps: - Step 1: Fetch the code from the PR branch. - Step 2: Run unit tests using Maven (a build tool for Java). If any test fails, the build fails and the developer gets an email. - Step 3: Build the application into a JAR file. - Step 4: Package the JAR into a Docker container image, tagging it with the commit hash (a unique identifier for the change). - Step 5: Push the container image to Artifact Registry. - Step 6: Deploy the image to a staging environment running on Google Kubernetes Engine.
The engineer also sets up a trigger that runs the pipeline automatically when code is pushed to the develop branch. For production releases, they create a separate trigger that only fires when a tag like v1.2.3 is pushed. That production trigger includes an extra step: running performance tests using Apache JMeter, which simulates hundreds of concurrent users. If the performance test fails, the build stops and does not deploy.
The team also integrates Cloud Build with Cloud Storage. Build logs are sent to Cloud Storage for audit. Artifacts — such as the JAR file — are stored there as well so that developers can inspect them later. The engineer configures a service account for Cloud Build with minimal permissions: it can read from the repository, write to Artifact Registry, and deploy to the staging GKE cluster. For production deployment, a separate service account requires a manual approval from the operations lead.
Now, six months later, the same checkout bug scenario happens. A developer pushes a fix for a broken product image link. The Cloud Build pipeline runs unit tests, which pass. Integration tests catch that the fix accidentally changed the shipping cost calculation for international orders. The build fails instantly. The developer gets a notification in their Slack channel, fixes the bug within ten minutes, and pushes again. The pipeline runs green. The fix reaches staging automatically and is approved for production the same day. No customer ever sees the broken behaviour.
The real world use of Cloud Build saves the company not just money but also developer time. Instead of spending two hours every Friday manually testing and deploying, they now spend two minutes reviewing merge requests. The team ships features five times faster, with fewer incidents. The PCD exam expects you to understand this workflow so you can architect similar pipelines for any organisation.
The PCD exam focuses on practical, scenario-based questions about Cloud Build. You will not be asked to write YAML from memory, but you will need to read a YAML snippet and identify what it does. Here is exactly what you need to master.
Trigger configuration is the most tested area. Questions will give you a scenario like: "A developer wants to build and test every push to any branch except 'main'." You need to know that you set a trigger with an include branch filter for .* (all branches) and an exclude branch filter for ^main$. Remember that branch filters use regular expressions. A common trap is forgetting that the tags field in a trigger filters on Git tags, not branches. Another trap: mistaking invertRegex — if you set invertRegex: true on a branch filter, the trigger fires for branches that do NOT match the pattern.
Service account permissions appear frequently. Cloud Build runs with a default service account called [PROJECT_NUMBER]@cloudbuild.gserviceaccount.com. The exam tests that you know you must grant this service account the roles needed to perform steps, like roles/artifactregistry.writer to push images or roles/run.invoker to deploy to Cloud Run. A common question: "Why does my build fail when it tries to deploy?" The answer is almost always that the Cloud Build service account lacks the appropriate IAM role on the target resource.
Build steps ordering and substitution variables are also key. You can use built-in substitution variables like $PROJECT_ID, $BUILD_ID, $REPO_NAME, and $COMMIT_SHA. Custom substitution variables start with _ (underscore) — for example, _DEPLOY_REGION. The exam may give you a YAML snippet with ${_VAR} syntax and ask what value the variable holds. You must understand that substitution happens at build time, not at YAML parse time.
Parallel and dependent steps appear in more advanced questions. Cloud Build uses waitFor in each step. By default, each step waits for all previous steps. You can set waitFor: ['-'] to run a step immediately (parallel to others), or you can specify a list of step names. A question might show a build that has two steps both with waitFor: ['-'] and ask if they run in parallel — the answer is yes.
Custom build steps are tested through scenarios where the default builders (like golang, node, python) do not have the tool you need. You then create your own builder image by writing a Dockerfile, building it, pushing it to Artifact Registry, and referencing it in cloudbuild.yaml. The exam loves to ask: "What is the first step to use a custom tool in Cloud Build?" The answer is always "create a custom builder image."
Logging and error handling questions appear less often but still matter. Cloud Build logs are sent to Cloud Logging by default. You can configure a timeout for the entire build (default 10 minutes, max 1440 minutes). If a step takes longer than a specified timeout, the build fails. The exam might ask: "Your build takes 15 minutes. Where should you increase the timeout?" You set it either in the cloudbuild.yaml under timeout or in the trigger settings.
Common exam traps to watch for: - Confusing a build trigger with a build step. A trigger defines *when* to run; a step defines *what* to run. - Thinking that Cloud Build automatically knows your repository. You must configure a connection to a source repository (like Cloud Source Repositories, GitHub, or Bitbucket). - Assuming that Cloud Build builds and deploys in one step. It builds in steps you define; deployment is just another step. - Forgetting that Cloud Build can be used for non-container builds (e.g., building a JAR and storing it in Cloud Storage). The exam may test that flexibility.
Key definitions to memorise:
- Trigger: A configuration that starts a build automatically based on events (push to branch, new tag, pull request).
- Build step: A single task run in a container, defined by a name, args, and optionally entrypoint, env, dir.
- Artifact Registry: Google Cloud's managed service for storing container images and other packages.
- Cloud Build service account: The identity that Cloud Build uses to access resources.
- Substitution variable: A placeholder that gets replaced at build time.
- WaitFor: The field that controls step dependency ordering.
Memorise these concepts cold. Practise reading YAML snippets from the official Cloud Build documentation. The exam is not about memorising the entire YAML schema but about reasoning through realistic scenarios where one misconfigured field causes a pipeline to fail.
Cloud Build runs build steps in order defined by the `waitFor` field; steps with `waitFor: ['-']` execute in parallel.
A build trigger specifies the event that starts a build — common triggers are branch pushes, tag pushes, and pull request events.
Cloud Build substitutes variables like `$PROJECT_ID` at build time; custom variables must start with an underscore and can be defined in the trigger or substitution file.
The Cloud Build service account needs explicit IAM permissions on resources like Artifact Registry, Cloud Run, or GKE to successfully deploy.
Unit tests run fastest and catch logic errors; integration tests catch service-level failures; end-to-end tests validate the full user experience.
A build fails if any step returns a non-zero exit code; you can set `entrypoint` to a script that handles partial failures gracefully.
Cloud Build logs are automatically sent to Cloud Logging for debugging; you can also stream logs in real-time via the `gcloud builds log` command.
For production safety, use separate triggers for production with manual approval required before the final deploy step.
These come up on the exam all the time. Here's how to tell them apart.
Continuous Integration (CI)
Focuses on merging code and running tests frequently.
Automatically builds and tests every code change.
Stops after tests pass; no automatic deployment.
Stops after tests pass; no automatic deployment.
Continuous Delivery (CD)
Focuses on automatically deploying verified code to an environment.
Often includes deployment to staging or production.
Requires CI to already be completed successfully.
Requires CI to already be completed successfully.
Cloud Build Trigger
Defines the event that starts the build (e.g., push, PR, schedule).
Configured outside the cloudbuild.yaml file (in Console or via API).
Can include branch filters, tag filters, and substitution variables.
Can include branch filters, tag filters, and substitution variables.
Cloud Build Step
A single task inside the pipeline (e.g., test, build, deploy).
Defined inside the cloudbuild.yaml file.
Runs inside a container with specified image and command.
Runs inside a container with specified image and command.
Default Cloud Build Service Account
Automatically created as [PROJECT_NUMBER]@cloudbuild.gserviceaccount.com.
Has basic permissions like Cloud Build Editor by default.
May lack permissions for specific resources like Artifact Registry or Cloud Run.
May lack permissions for specific resources like Artifact Registry or Cloud Run.
Custom Service Account for Cloud Build
Create a dedicated service account with least-privilege permissions.
You assign exact roles needed (e.g., Storage Object Admin, Run Invoker).
More secure and recommended for production pipelines.
More secure and recommended for production pipelines.
Unit Tests
Test a single function or method in isolation.
Run very fast (milliseconds per test).
No external dependencies like databases or APIs needed.
No external dependencies like databases or APIs needed.
Integration Tests
Test how multiple components work together (e.g., service and database).
Run slower (seconds to minutes per test).
Require test environments with real dependencies.
Require test environments with real dependencies.
Mistake
CI and CD are the same thing – both just mean automated testing.
Correct
CI (continuous integration) is about frequently merging code and running tests to catch integration issues. CD (continuous delivery or deployment) is about automatically deploying that verified code to an environment.
People see the terms used interchangeably in many articles and blog posts, especially when services like Cloud Build bundle both concepts into a single tool.
Mistake
Cloud Build can only build Docker containers.
Correct
Cloud Build can run any step inside any container image. You can compile a Java JAR, run a Python script, upload a file to Cloud Storage, or even send a Slack notification. Creating a new container image is optional.
Most tutorials and exam examples focus on building and pushing Docker images, so beginners assume that is the only purpose.
Mistake
You must have a separate Cloud Build instance per environment (dev, staging, prod).
Correct
A single Cloud Build project can run builds for all environments. You differentiate by using different triggers with different branch or tag filters, and by passing different substitution variables (like `_ENVIRONMENT=staging`).
Many developers are used to managing separate VM instances for each environment, so they naturally assume the same pattern applies to managed services.
Mistake
If the build fails, Cloud Build automatically retries it.
Correct
Cloud Build does not automatically retry failed builds. You must configure a retry strategy manually, either by setting up a Cloud Scheduler job that re-runs the build, or by using a custom script in the build step that checks failures and retries.
Some CI tools like Jenkins have built-in retry options, so people assume Cloud Build works the same way.
Mistake
Cloud Build can only be triggered by Git pushes.
Correct
Cloud Build supports multiple trigger types: push to a branch, new tag, pull request creation/update, manual invocation, Cloud Pub/Sub messages, and scheduled builds via Cloud Scheduler.
Beginners often first encounter Cloud Build through a GitHub integration and never explore other trigger options.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
You can set environment variables directly in the `env` field of a build step, or use substitution variables like `$_MY_VAR` defined in the trigger. Secrets should be stored in Secret Manager and accessed via the `availableSecrets` field in your cloudbuild.yaml.
Yes, you can install the `cloud-build-local` tool (part of the Cloud SDK) or use the `gcloud builds submit` command with a local config file to simulate the build in Google Cloud without needing a trigger.
A build step is a single task inside the pipeline (e.g., run tests, build an image). A build trigger is the configuration that tells Cloud Build when to start the pipeline (e.g., a push to the main branch).
The build fails. You can increase the timeout in the `cloudbuild.yaml` file using the `timeout` field (up to 24 hours), or in the trigger settings. The default timeout is 10 minutes.
If a step returns a non-zero exit code, the build stops and is marked as failed. Subsequent steps do not run. You can use the `allowFailure` field in a step to let the build continue even if that step fails, but this is rarely recommended for tests.
Absolutely. Cloud Build can run any step in any container. For a static website, you could use a step that runs a script to minify CSS and HTML, then a step that copies the files to a Cloud Storage bucket. No container image needs to be built.
You've finished Application Testing and CI/CD Pipelines. Continue through the PCD study guide to build a complete picture of the exam.
Done with this chapter?