Prepare and test your skills
Prepare and test your skills
Setting up your development environment means preparing local tools, cloud interfaces, and development workspaces (opens in a new tab) so code can be written, tested, and deployed without affecting production. The setup connects a developer machine to Google Cloud through authentication, project selection, and local simulations of cloud services. Traffic flows from the application to either a local emulator for testing or to Google Cloud for real execution, depending on configuration.
Local emulators are high-fidelity simulations of production database and messaging services that run on a developer machine. The Google Cloud software development kit (SDK) distributes emulator components, and gcloud emulators commands start local instances that listen on localhost. The emulator creates an isolated test boundary where data exists only for the session, so test writes never reach production and do not consume quota.
| Emulator | Start command | Default local endpoint |
|---|---|---|
| Bigtable emulator | gcloud beta emulators bigtable start | localhost:8086 |
| Cloud Spanner emulator | gcloud emulators spanner start | localhost:9010 for gRPC and localhost:9020 for REST |
| Pub/Sub emulator | gcloud beta emulators pubsub start --project=PUBSUB_PROJECT_ID | Port 8085 on IPv6 localhost ::1 |
Installation must finish before any endpoint can start, using gcloud components commands to add binaries. When several emulators run together, each start command must set its host and port explicitly to avoid conflicts. Pub/Sub can listen on all addresses with --host-port=0.0.0.0:8085 or on IPv4 with --host-port=127.0.0.1:8085, and Docker can map the same host ports into containers.
Connecting applications to emulators means pointing Cloud Client Libraries from production endpoints to the local endpoint with an environment variable. The library checks the variable when the application starts and sends creates, reads, writes, publishes, and subscribes to the emulator if the variable is present. When the variable is absent, the same code flows to the production Google Cloud endpoint with no code change.
The Bigtable path sets BIGTABLE_EMULATOR_HOST=localhost:8086, the Cloud Spanner path sets SPANNER_EMULATOR_HOST=localhost:9010, and the Pub/Sub path sets PUBSUB_EMULATOR_HOST. The Spanner variable can be set with $(gcloud emulators spanner env-init) and the Pub/Sub variable with $(gcloud beta emulators pubsub env-init). The Bigtable emulator does not provide administrative APIs for instances and clusters, does not support a secure connection, and cannot be used in the HBase shell.
The ordered local test workflow is:
Stopping the foreground process with Control-C ends session-scoped state such as Bigtable in-memory tables and Pub/Sub topics and messages. After testing, unset the variable so later runs return to production behavior. Pub/Sub accepts unencrypted http push endpoints locally, while production requires secure https endpoints.
The Google Cloud console, Cloud Shell, and Google Cloud command-line interface (CLI) are three interfaces that call the same underlying Google Cloud APIs. The console is the browser graphical hub for creation, Identity and Access Management (IAM), billing, and monitoring. Cloud Shell is a browser terminal with the CLI preinstalled and the current project already selected, running on a virtual machine (VM) that Google provisions each session with a persistent $HOME directory. A local CLI requires gcloud init and manual project selection for scripted or continuous integration and continuous delivery (CI/CD) work.
A standard setup workflow moves from identity to project to defaults to access:
gcloud init to authenticate and select initial defaults.gcloud projects create PROJECT_ID, then gcloud config set project PROJECT_ID.gcloud config set compute/region REGION and gcloud config set compute/zone ZONE.gcloud config list, and use gcloud config configurations create NAME for separate named configurations.gcloud iam service-accounts create SERVICE_ACCOUNT_NAME for workloads.gcloud projects add-iam-policy-binding with the member and --role for each required role.Cloud Code is an integrated development environment (IDE) extension that brings Google Kubernetes Engine (GKE) and Cloud Run into the editor for creating, running, deploying, and monitoring apps. It runs in Visual Studio Code, IntelliJ and other JetBrains IDEs, and Cloud Shell Editor, and supports Go, Java, Node.js, Python, and .NET Core. Gemini Code Assist generates code and inline suggestions inside Cloud Code, while Gemini Cloud Assist helps design, deploy, troubleshoot, and optimize across the lifecycle. Gemini Code Assist is a separate plugin that requires a selected Google Cloud project with IAM permissions.
Cloud Workstations is a managed development environment service that provides secure, preconfigured cloud IDEs on Compute Engine VMs inside the team's project and Virtual Private Cloud (VPC) network. Platform teams define the environment once, and developers launch instances through a browser IDE, local VS Code or IntelliJ, or Secure Shell (SSH). Resources form a three-level hierarchy with different owners:
A workstation session moves through an ordered lifecycle where compute is ephemeral and data persists: first Cloud Workstations creates an ephemeral VM and attaches the home disk, then the developer codes and saves files to that disk, then stopping deletes the VM and detaches the disk, and restarting provisions a fresh VM and reattaches the same disk. Client traffic flows from the developer client to the cluster gateway to the VM gateway to the container, with authentication at the VM gateway. The cluster gateway is public by default but can be made fully private, and VPC firewall rules, flow logs, and controls limit exfiltration.
IDE authentication connects the editor, cloud project, and AI assistant through one identity. The Google Cloud SDK includes the CLI, Cloud Client Libraries, IDE extensions, and emulators, and requires a Cloud Identity or Google Workspace user, IAM roles, and billing. Setup depends on order: first install the CLI, then run gcloud init to sign in the CLI, then run gcloud auth application-default login to create the Application Default Credentials (ADC) file used by application code.
Inner-loop development with Cloud Code means editing, building, running, and observing containerized apps without leaving the IDE. Local GKE work uses minikube and Skaffold modules with dependencies between skaffold.yaml files, while local Cloud Run work uses the built-in Cloud Run emulator before deploying to hosted Cloud Run. Secret values flow from Secret Manager to the running app at runtime while code holds only a reference. Builds often use buildpacks to create images without a Dockerfile, then deploy with Skaffold and kubectl or Cloud Run Explorer.
Exam tip: gcloud init signs in the gcloud CLI and selects the default project, while gcloud auth application-default login creates the credentials file that local application code uses to call Google APIs.
Continue with this study guide: Setting up your development environment
Building applications means turning source code into versioned container images, storing them securely, and proving they are trusted before deployment. Cloud Build compiles source into images and checks them for vulnerabilities, while Artifact Registry stores the images where GKE, Cloud Run, and Compute Engine can pull them. The chain flows from builder to registry to admission control at deploy time.
Building images from source to Artifact Registry is the secure transfer of a built image to an address like LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME. The simplest path runs gcloud builds submit --tag LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME from a directory with source and a Dockerfile, which builds and pushes without a config file. A build config gives more control by defining steps that run builders such as gcr.io/cloud-builders/docker, with each step container attached to a local Docker network named cloudbuild.
| Storage option | What it stores | Visibility in build results |
|---|---|---|
images field | Docker image pushed after the build completes | Shown on the Build description page and in gcloud builds list |
docker push step | Container image pushed during the step sequence | Not shown in build results |
artifacts.oci field | Open Container Initiative (OCI) image folder with file and registryPath | Stored as OCI artifact with optional tags |
Choose the images field when visibility in build results matters, and choose docker push when the push must happen at a specific point, such as only after a vulnerability check passes. To make an image available to later steps and still show it in results, include both with the same image path.
Exam tip: An image stored with the images field appears in Cloud Build results, while an image stored with a docker push step does not.
A cloudbuild.yaml file defines automation through its steps field, where each step runs a container as an instance of docker run. Each step names a builder image in name and passes tool commands in args, and by default Cloud Build runs all steps serially on the same machine. A config can include up to 300 steps with up to 100 arguments per step.
A typical containerization pipeline moves source through an ordered sequence: first a docker builder runs docker build from the Dockerfile and workspace source, then a second docker builder runs docker push with the same Artifact Registry path, then a later step uses another builder such as gcr.io/google.com/cloudsdktool/cloud-sdk to scan or deploy. Steps share data through the /workspace directory, so one step can write an image digest that a later step reads. Use id to name steps, waitFor to allow concurrency, and -f DOCKERFILE_PATH when the Dockerfile lives outside the source directory.
Substitution variables let one cloudbuild.yaml file target different projects and environments without editing the file. Custom substitutions start with an underscore, such as $_IMAGE and $_SEVERITY, and are declared in a top-level substitutions map with defaults. Built-in values such as ${PROJECT_ID} and ${BUILD_ID} resolve automatically, so the path adapts to the project that runs the build.
The build depends on options flags to control how substitutions flow into containers. Setting dynamicSubstitutions: true allows values like ${BUILD_ID} to resolve correctly, while automapSubstitutions: true maps substitutions into the container environment. Setting substitutionOption: ALLOW_LOOSE tells Cloud Build to ignore unused substitutions instead of failing. The same goal can start with a config file using gcloud builds submit --config CONFIG_FILE_PATH SOURCE_DIRECTORY, with only a Dockerfile using --tag, or with buildpacks using --pack image=LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME. Build triggers extend this by watching Cloud Source Repositories, GitHub, or Bitbucket and starting automatically on pushes or pull requests.
Scanning images and enforcing deploy-time integrity keeps vulnerable or unproven images out of production. Automatic vulnerability scanning scans images when uploaded to Artifact Registry and monitors them for new vulnerabilities for up to 30 days after the push. The On-Demand Scanning API scans when gcloud artifacts docker images scan is called, so Cloud Build can scan after the build and block the push if a blocked severity is found.
A secure pipeline orders build, scan, check, and push so only clean images are stored: first build the image and record its digest, then call the On-Demand Scanning API and save the scan ID, then check vulnerability.effectiveSeverity and fail with exit 1 if a blocked severity is found, then push to Artifact Registry only if the check succeeded. The gate blocks only levels in _SEVERITY with values CRITICAL, HIGH, MEDIUM, and LOW, and matching is exact, so blocking HIGH and above requires CRITICAL|HIGH. At deploy time, Binary Authorization allows deployment only with required proof, using ephemeral workers destroyed after each build and Supply Chain Levels for Software Artifacts (SLSA) Level 3 provenance.
Docker repositories in Artifact Registry are regional or multi-regional containers for related images, addressed as LOCATION-docker.pkg.dev/PROJECT/REPOSITORY/IMAGE:TAG. Teams create separate repositories for testing, staging, or production and control access at the repository level. Images are versioned by tags and manifest digests, each Dockerfile instruction creates a layer, images in the same registry reuse shared layers, and the target repository must already exist before a push.
Access control grants IAM roles on individual repositories, unlike Container Registry which used Cloud Storage roles on the whole host. The default Cloud Build service account can upload and download in the same project, while the Compute Engine default service account used by GKE nodes and Cloud Run can pull in the same project. Cross-project pushes require the Artifact Registry Writer role. Repositories support customer-managed encryption keys (CMEK), VPC Service Controls perimeters, Pub/Sub notifications, and image streaming to reduce GKE cold-start latency. Efficient Dockerfiles order stable dependency steps before changing code, and Java and .NET use multi-stage builds where only final output enters a smaller runtime image.
Configuring provenance means generating verifiable build metadata and enforcing it so only trusted digests run. An attestor represents a trusted authority with a note and public key, and an attestation is a signed statement that a specific immutable digest like IMAGE_PATH@sha256:37e528... passed its requirements. An attestation authorizes the digest, not the mutable tag, and is enforced only when the Binary Authorization policy names those attestors. Setup follows an ordered dependency: enable Binary Authorization, create attestors with Cloud Key Management Service (Cloud KMS) keys, configure the policy rule, sign each digest, then deploy to GKE or Cloud Run where signatures are verified. Cloud Build provenance describing builder identity and dependencies is stored in Artifact Analysis as a BUILD occurrence linked by invocation ID containing project, location, and build ID.
Continue with this study guide: Building
Writing and executing tests means proving that application code behaves correctly before it is merged and deployed. Creating test cases (opens in a new tab) for a single function checks expected logic in isolation, while automated integration tests in Cloud Build verify that components work together in ordered containers. Test evidence then decides whether artifacts are published or deployments proceed.
Generating draft tests with AI assistants starts with a prompt that contains the function under test and a clear instruction. In one example, the prompt Write a unit test for this function: is followed by the Python is_leap_year(year) function and sent with temperature 0.5 and maxOutputTokens 256 to the code-bison@001 model through the Vertex AI prediction service. Cloud Code provides this workflow inside the IDE by integrating with Gemini Code Assist Standard and Enterprise, which generates code and inline suggestions. The assistant is not auto-enabled and requires connecting to Google Cloud, selecting a project, and enabling IAM permissions.
The generated output is only a starting proposal because generative models have randomness, so identical inputs may produce different results. Human validation treats every suggestion as untrusted until it is executed and refined against real behavior. Checking accuracy means verifying the full decision chain, such as divisible by 4 except by 100 except by 400 for leap years, plus happy paths and failure paths. This follows the shift-left principle where fixing bugs during development avoids customer impact, with flow from writing code and tests to presubmit checks to human review to shared repository.
Adding edge cases and runtime checks is the manual step where developers add inputs that AI drafts usually miss. Fuzzing complements unit tests by bombarding an application with random inputs to expose crashes or security flaws, while adversarial testing, subgroup analysis, and continuous monitoring validate generative behavior. Boundary tests cover invalid types, null values, out-of-range numbers, and failed dependencies. Static analysis finds risky patterns without running code, while dynamic analysis runs code to uncover runtime issues with tools including AddressSanitizer for memory errors, ThreadSanitizer for data races in C++ and Go, and MemorySanitizer for uninitialized memory use.
Isolating tests with mocks and emulators means replacing live Google Cloud dependencies with locally controlled doubles so failures point to code defects rather than network or permissions. An AI assistant can draft mock code using Cloud Client Libraries for Go, Java, Node.js, Python, and .NET Core, but generated mocks must be reviewed for invented methods or missing error paths. Google Cloud SDK emulators provide higher fidelity where requests flow from the test to the local emulator and responses flow back without crossing a production trust boundary. Choose lightweight mocks for speed and pure isolation, and choose an emulator for behavioral fidelity such as Firestore queries or Pub/Sub messaging.
Contextual prompts must supply function signature and body, data schemas with valid and invalid values, and named cloud dependencies so the model can mock instead of calling live services. A programmatic call packages the prompt as instance and parameter values, builds an endpoint name from project, location, publisher google, and model code-bison@001, then calls predictionServiceClient.predict against us-central1-aiplatform.googleapis.com:443.
Defining ordered pipelines with build config files means declaring source, suites, and artifacts in cloudbuild.yaml or cloudbuild.json. Each entry in the steps list selects a container image in name, passes arguments in args, and can override the command in entrypoint. Cloud Build runs steps in listed order and stops the build when a step fails, so later steps depend on earlier test success.
The standard lifecycle flows in a fixed order: first prepare code and assets such as requirements.txt and a Dockerfile, then create the YAML or JSON config, then submit manually with the gcloud CLI or automatically with triggers for GitHub and Bitbucket, then execute each step as a Docker container, then publish images to Artifact Registry and logs to Cloud Storage. Each step runs in its own isolated container on a fresh VM worker that is destroyed afterward, which improves reproducibility and security. The name field controls available tools, such as gcr.io/cloud-builders/docker for Docker, python with pip for Python tests, and google/cloud-sdk for gcloud commands. A Python pipeline often runs pip install -r requirements.txt --user before running python -m pytest --junitxml=${SHORT_SHA}_test_log.xml, with substitutions tagging outputs by commit.
| Test type | Scope | Choose when |
|---|---|---|
| Unit testing | Single function or method in isolation | The goal is to verify logic, branches, and edge cases |
| Integration testing | Interaction between components or modules | The goal is to verify mocked clients and real code together |
| End-to-end testing | Full application in a realistic scenario | The goal is to simulate user journeys after lower tests pass |
Every build-step container attaches to a local Docker network literally named cloudbuild, allowing test containers to reach temporary dependency containers without external infrastructure. All linked services disappear when the VM is destroyed. If the build needs private-network resources, it depends on a private pool of dedicated workers with private access.
Protecting credentials with Secret Manager means storing passwords and API keys outside source and build files. Integration tests record the secret name and version, enable the Cloud Build and Secret Manager APIs, and grant the build service account the Secret Manager Secret Accessor role on the specific secret. Granting this role to the legacy Cloud Build service account carries extra risk because trigger users inherit its permissions at build time. Mapping connects a secret version to an environment variable through an availableSecrets field with versionName and env, and the test step declares use through secretEnv.
Access is granted in the console by opening Secret Manager, selecting the secret, opening the info panel, adding the build service account as principal, selecting Secret Manager Secret Accessor, and saving. Using test results as quality gates means test evidence decides whether later work runs. The artifacts.objects field copies JUnit logs to Cloud Storage such as gs://${_BUCKET_NAME}/, while the images field pushes containers to Artifact Registry and surfaces them in results. A typical routine copies source to /workspace, runs tests with optional Pylint, builds Docker images tagged with $COMMIT_SHA only if tests pass, publishes artifacts, and optionally runs an end-to-end deployment test. A failed step fails the whole build and shows Failure status with a Details link to logs.
Exam tip: A build step can only read a mapped secret when it sets secretEnv for that variable, uses the bash entrypoint, and starts args with -c.
Continue with this study guide: Testing
BIGTABLE_EMULATOR_HOST, SPANNER_EMULATOR_HOST, and PUBSUB_EMULATOR_HOST pointing client libraries to local endpoints, and unsetting the variable returns the same code to production.LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME, with the images field surfacing pushes in build results.steps in order as isolated containers on the cloudbuild network, and a step reads Secret Manager secrets only with secretEnv, bash entrypoint, and args starting with -c.Set the matching host environment variable to the local endpoint so Cloud Client Libraries send traffic to the emulator, and unset the variable to return the same code to production without code changes. The Bigtable path uses BIGTABLE_EMULATOR_HOST with localhost:8086, the Cloud Spanner path uses SPANNER_EMULATOR_HOST with localhost:9010, and the Pub/Sub path uses PUBSUB_EMULATOR_HOST. The ordered workflow is to start the emulator, set the variable, run reads, writes, publishes, and subscribes locally, then stop the emulator and unset the variable.
gcloud init signs in the gcloud command-line interface and selects the default project, while gcloud auth application-default login creates the Application Default Credentials file that local application code uses to call Google APIs. Setup depends on order with installation first, then gcloud init, then gcloud auth application-default login.
Use the images field when visibility in build results matters because images pushed with the images field are shown on the Build description page and in gcloud builds list, while images pushed with a docker push step are not shown. Use a docker push step when the push must happen at a specific point such as only after a vulnerability check passes, and include both with the same image path to make an image available to later steps and still show it in results.
Last updated