Runtime Configuration

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

See the section bibliography for the reference material consulted while preparing these pages.

Commands and behaviour on this page are current for the gcloud CLI 586.x line (gcloud parametermanager command group, GA since 2025-03-27), Cloud Run and GKE 1.35 (Regular channel) documentation, Config Sync as included in GKE since 2025-09-02, Spring Cloud GCP 8.x for Spring Boot 4 (7.4.x for Spring Boot 3) and Terraform hashicorp/google v8 (checked 2026-10-01); re-verify against gcloud version, gcloud parametermanager --help and the linked reference pages before relying on them in a pipeline. Examples use the placeholder project my-project-id, the placeholder project number 123456789012 and the region us-central1; all are stand-ins for your own values.

Most of what a running service needs to know is not code: a page size, an upstream timeout, the address of another service, a switch that turns a new screen on for a tenth of the traffic. This page covers the Google Cloud ways to keep such values outside the build and, where it is worth the machinery, to change them while the service keeps running: Parameter Manager (versioned configuration with references to secrets), environment variables and secret volumes on Cloud Run, ConfigMaps and Config Sync on GKE, and a short look at feature-flag services. Secrets themselves — the database password, the SendGrid API key, Cloud KMS — are deliberately not repeated here; they live on Secret Manager and Cloud KMS, and this page only shows how the mechanisms below reference them. Application-side loading in Spring Boot (property-source order, @ConfigurationProperties, @RefreshScope, the Kubernetes ConfigMap and secret imports) is on Configuration and Profiles, and the Kubernetes objects themselves are on ConfigMaps. For the counterparts on other clouds see Runtime Configuration and Runtime Configuration.

The problem: configuration, secrets and flags

Bookshelf’s catalog-api (Cloud Run), orders-api (GKE Autopilot) and notifier (Cloud Run function) need three different kinds of values, each with its own owner and change cadence:

  • Plain configuration — a log level, a page size, an upstream URL. Not sensitive, reviewable in a diff.

  • Secrets — the database credential, a third-party API key. Never plaintext at rest, access audited. Stored in Secret Manager and only referenced by the mechanisms on this page.

  • Feature flags — a boolean (or a value chosen per request or per user) that turns behaviour on without a build, so a feature ships dark, is switched on for a slice of traffic, then for everyone, then removed.

All three vary per environment (dev, staging, prod), and teams increasingly want to change some of them without a rebuild. Those wishes pull in different directions: a value baked into a container image or a deployment manifest is trivially reviewable and reproducible but needs a rollout; a value fetched at run time changes in minutes but can break production without a pipeline noticing. The mechanisms below sit at different points on that line. Older guides for Google Cloud only show environment variables on Cloud Functions; the managed, versioned service added since is Parameter Manager, and the old Runtime Configurator is retired (see The retired Runtime Configurator).

Diagram of Parameter Manager holding the bookshelf-settings parameter and referencing Secret Manager secrets

Choosing a mechanism

Mechanism Best for Change takes effect Watch out for

Cloud Run environment variables

A handful of per-environment scalars (LOG_LEVEL, CATALOG_PAGE_SIZE)

On the next revision; every change creates one

Visible in the console and describe output, so never a secret value

Cloud Run secret as environment variable

A credential an app reads once at startup

On the next revision; pinned to a version

latest is resolved when an instance starts, not afterwards

Cloud Run secret volume

A whole config file, or a credential that must rotate without a redeploy

On the next read of the file (the volume always reads the latest version)

Regional secrets are not supported on Cloud Run

Parameter Manager

Structured configuration (YAML or JSON) shared by several services, with named versions and rollback

When a client reads or renders a version; you decide how often

One more call (and one more IAM grant) at startup or refresh time

Kubernetes ConfigMap

Pod configuration on GKE as environment variables or files

Environment variables: next pod start. Mounted files: eventually, without restart, unless subPath is used

Needs a rollout for env vars; objects are not versioned by Kubernetes

Config Sync

The same ConfigMaps and policies on many clusters, from Git or an OCI image

On the next reconcile after a commit

A GitOps repository is the source of truth; do not edit ConfigMaps by hand

Firebase Remote Config, OpenFeature

Feature flags and per-user or per-percentage rollouts

When a client fetches or a provider streams the change

Another service to operate; flags need an owner and an expiry date

A practical default for Bookshelf: put scalars in environment variables set by the deployment pipeline, put anything structured or shared in one Parameter Manager parameter named bookshelf-settings, keep credentials in Secret Manager and refer to them from there, and add a flag service only when someone actually needs per-user rollout.

Parameter Manager

Parameter Manager is the Google Cloud service for application configuration. It is part of the Secret Manager product family (the console entry is under Security, next to Secret Manager) and became generally available on 2025-03-27. It stores each piece of configuration as a parameter with an ordered series of parameter versions, so a change is a new version and a rollback is "point the application at the previous version".

Concepts

Parameter

A named container for one logical configuration, such as bookshelf-settings. A parameter has a format fixed at creation: YAML, JSON or UNFORMATTED (any text). The names allow letters, digits, dashes and underscores, up to 63 characters, and cannot start with a dash.

Parameter version

One immutable payload of a parameter, with a version ID you choose (v1, 2026-10-01, up to 63 characters). Versions can be disabled and deleted. The alias latest selects the newest version; production code usually names a version explicitly so a bad edit cannot reach it by accident.

Global and regional parameters

A parameter is either global (location global) or regional (for example us-central1). Regional parameters keep their data in one region and use regional endpoints, which matters for data residency; global parameters are the simpler default. The location is part of the parameter’s identity and cannot be changed.

Secret references

In a YAML or JSON parameter a value can point to a Secret Manager secret version instead of containing it. The reference is written as REF("//secretmanager.googleapis.com/projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSION"). Parameter Manager resolves it when the version is rendered, so the secret never appears in the parameter’s stored payload, and Secret Manager keeps its own versioning, rotation and audit trail. Limits at the check date: a parameter version can hold up to 15 secret references, references work only in structured formats, and the referenced secret’s content must not itself be YAML or JSON.

Render

Reading a version in two forms: the payload as stored (with the REF text still in it) and the rendered payload with the secrets substituted. Rendering needs a different permission from reading the raw payload (see [parameter-manager-iam]).

Templates

Reusable parameter templates with their own versions, in Preview at the check date. Treat them as a way to standardise the shape of many similar parameters, and check the launch stage before depending on them.

Launch stages, pricing and quotas

Parameter Manager is generally available; its template feature is in Preview. Pricing is a small charge per stored parameter version and per access operation, with a monthly free allowance; the numbers change, so read the dated Secret Manager and Parameter Manager pricing page instead of copying figures from a blog post. The cost drivers are the number of versions you keep and how often the applications read them, so cache a rendered value for the life of a request batch or a few minutes rather than rendering per request. Quotas (versions per parameter, payload size, requests per minute) are listed on the quotas and limits page; request an increase there if a large fleet reads at startup in lockstep.

In the Google Cloud console

  1. Select the project in the project picker, open Security > Secret Manager and choose the Parameter Manager tab (enable the Parameter Manager API when prompted, or enable it with the CLI first).

  2. Choose Create parameter. Enter bookshelf-settings, pick the format YAML, and choose Global (or a region for a regional parameter). Optionally add labels such as app=bookshelf and env=prod.

  3. Open the new parameter and choose New version. Name it v1, paste the YAML payload shown below, and save.

  4. To check a secret reference, open the version and choose View rendered; the console shows the payload with the secret values substituted only if your principal holds the accessor roles.

  5. Under Permissions, grant roles/parametermanager.parameterAccessor to the service accounts that read the parameter (for example the Cloud Run service identity of catalog-api).

With the gcloud CLI

Enable the API, create a YAML parameter and add the first version from a file. The payload has plain settings and one reference to the catalog-db-password secret created on Secret Manager and Cloud KMS:

export PROJECT_ID=$(gcloud config get-value project)   # placeholder: my-project-id
export PROJECT_NUMBER=$(gcloud projects describe "$PROJECT_ID" --format='value(projectNumber)')

gcloud services enable parametermanager.googleapis.com secretmanager.googleapis.com

gcloud parametermanager parameters create bookshelf-settings \
  --location=global \
  --parameter-format=YAML \
  --labels=app=bookshelf,env=prod

Derived from Create a parameter.

# settings-v1.yaml
catalog:
  pageSize: 25
  logLevel: INFO
  upstreamTimeoutMs: 2500
db:
  host: 10.20.0.5
  user: catalog_app
  password: __REF__("//secretmanager.googleapis.com/projects/my-project-id/secrets/catalog-db-password/versions/3")
gcloud parametermanager parameters versions create v1 \
  --parameter=bookshelf-settings \
  --location=global \
  --payload-data-from-file=settings-v1.yaml

gcloud parametermanager parameters versions list \
  --parameter=bookshelf-settings --location=global

# Read the raw payload (secret reference text still in it)
gcloud parametermanager parameters versions describe v1 \
  --parameter=bookshelf-settings --location=global

Regional parameters use the same commands with --location=us-central1. Rollback is not a command of its own: create a new version with the earlier payload (or disable the bad version) and move the consumers back to the earlier ID.

Granting access and rendering

Three different principals are involved, and the third is the one people forget:

Who Needs Why

People or pipelines that edit configuration

roles/parametermanager.parameterAdmin (or parameterVersionAdder for append-only)

Create parameters and add versions

Applications that only read

roles/parametermanager.parameterViewer for the raw payload, roles/parametermanager.parameterAccessor to render

Least privilege on the parameter, not the project

The parameter itself

roles/secretmanager.secretAccessor on each referenced secret

Parameter Manager resolves REF using the parameter’s own identity, not the caller’s

The parameter’s principal identity is shown on the parameter’s page and returned by describe; it has the form principal://parametermanager.googleapis.com/projects/PROJECT_NUMBER/uid/locations/global/parameters/PARAMETER_UID. Grant it access to the secret (and only to the secrets it references), and give the application read access to the parameter:

# Identity of the parameter (global parameters)
PARAM_UID=$(gcloud parametermanager parameters describe bookshelf-settings \
  --location=global --format='value(policyMember.iamPolicyUidPrincipal)')

# 1. Let the parameter resolve the secret reference
gcloud secrets add-iam-policy-binding catalog-db-password \
  --member="$PARAM_UID" \
  --role="roles/secretmanager.secretAccessor"

# 2. Let catalog-api's service account render the parameter
gcloud parametermanager parameters add-iam-policy-binding bookshelf-settings \
  --location=global \
  --member="serviceAccount:catalog-api@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/parametermanager.parameterAccessor"

# 3. Render: the payload is returned base64-encoded in the response
gcloud parametermanager parameters versions render v1 \
  --parameter=bookshelf-settings --location=global

Derived from Reference Secret Manager secrets in a parameter and Render a parameter version. The exact field that carries the principal identifier can differ between gcloud releases; if the --format expression above prints nothing, run describe without it and copy the principal:// value shown.

Terraform alternative

resource "google_parameter_manager_parameter" "settings" {
  parameter_id = "bookshelf-settings"
  format       = "YAML"
  labels       = { app = "bookshelf", env = "prod" }
}

resource "google_parameter_manager_parameter_version" "v1" {
  parameter            = google_parameter_manager_parameter.settings.id
  parameter_version_id = "v1"
  parameter_data       = file("${path.module}/settings-v1.yaml")
}

resource "google_secret_manager_secret_iam_member" "param_reads_secret" {
  secret_id = google_secret_manager_secret.catalog_db_password.id
  role      = "roles/secretmanager.secretAccessor"
  member    = google_parameter_manager_parameter.settings.policy_member[0].iam_policy_uid_principal
}

Derived from the google_parameter_manager_parameter resource page of the hashicorp/google provider.

Reading a parameter from Java

The Google Cloud Client Libraries include a Parameter Manager client (google-cloud-parametermanager, managed by the libraries-bom). It uses Application Default Credentials, so on Cloud Run and GKE it picks up the attached service account or Workload Identity Federation for GKE without any key file. For local work, impersonate a service account instead of downloading a key (gcloud auth application-default login --impersonate-service-account=…​).

package com.example.bookshelf.config;

import com.google.cloud.parametermanager.v1.ParameterManagerClient;
import com.google.cloud.parametermanager.v1.ParameterVersionName;
import com.google.cloud.parametermanager.v1.RenderParameterVersionResponse;
import java.io.IOException;

public final class SettingsLoader {

    /** Renders a YAML parameter version, with secret references already resolved. */
    public String loadRendered(String projectId, String parameterId, String versionId)
            throws IOException {
        try (ParameterManagerClient client = ParameterManagerClient.create()) {
            ParameterVersionName name =
                    ParameterVersionName.of(projectId, "global", parameterId, versionId);
            RenderParameterVersionResponse response = client.renderParameterVersion(name);
            return response.getRenderedPayload().toStringUtf8();
        }
    }
}

Derived from the Parameter Manager overview and its client library samples; check the package and method names against the library version your libraries-bom selects. Regional parameters need a client built with the regional endpoint (ParameterManagerSettings.newBuilder().setEndpoint("parametermanager.us-central1.rep.googleapis.com:443")).

Spring Boot integration: at the check date there is no Parameter Manager property source in the Spring Cloud GCP starters comparable to the sm@ Secret Manager import (see Secret Manager and Cloud KMS), so verify the current starter documentation before assuming one. The reliable pattern is to render the YAML in a small bean or EnvironmentPostProcessor at startup, parse it and expose it through @ConfigurationProperties as described on Configuration and Profiles. An alternative that needs no code is to render the parameter before the process starts (see the Cloud Run and GKE sections below) and point Spring at the resulting file with spring.config.import=optional:file:/etc/config/settings.yaml.

Refresh strategies

Parameter Manager does not push changes to running code, and at the check date it has no change notification of its own to subscribe to, so choose one of these:

  • Read at startup, change by revision. Render the pinned version when the instance starts; to change configuration, create a new version and roll a new Cloud Run revision or Kubernetes rollout that names it. Simple, auditable, rollback is a redeploy. This is the default recommendation.

  • Poll. A scheduled task re-renders latest (or a version named in a feature flag) every few minutes and swaps an in-memory snapshot. Combine with @RefreshScope or a rebuilt @ConfigurationProperties bean. Cost is one access operation per poll per instance; add jitter so a fleet does not poll in lockstep.

  • Event-driven. Secret Manager can publish Pub/Sub notifications when a secret version is added; a parameter referencing that secret can be re-rendered in the subscriber. Parameter versions themselves do not publish events at the check date, so a push model for plain configuration means your pipeline publishes a message after versions create.

Cloud Run

Cloud Run takes configuration from the service definition: environment variables, secrets exposed as environment variables or volumes, and mounted volumes. Every change to any of these creates a new revision, so configuration changes are rollouts that can be rolled back, traffic-split and tested like code. The mechanics of revisions and traffic are on Cloud Run Scaling, Traffic and Jobs; service basics are on Cloud Run. Functions deployed as Cloud Run functions take the same flags; see Cloud Run Functions and Events.

In the Google Cloud console

  1. Open Cloud Run, select the service catalog-api, and choose Edit & deploy new revision.

  2. On the Containers tab, open Variables & Secrets. Under Environment variables choose Add variable and enter CATALOG_PAGE_SIZE = 25 and LOG_LEVEL = INFO.

  3. Under Secrets choose Reference a secret, pick catalog-db-password, and select either Exposed as environment variable (name DB_PASSWORD, version 3) or Mounted as volume (mount path /etc/secrets, version latest).

  4. Choose Deploy. The console shows the new revision and, if you do not send all traffic to it, you can keep the previous revision serving until you verify the change.

With the gcloud CLI

export REGION=us-central1
export SERVICE=catalog-api

# Replace all environment variables (variables not listed are removed)
gcloud run services update "$SERVICE" --region="$REGION" \
  --set-env-vars=CATALOG_PAGE_SIZE=25,LOG_LEVEL=INFO

# Add or change one variable, keep the rest
gcloud run services update "$SERVICE" --region="$REGION" \
  --update-env-vars=LOG_LEVEL=DEBUG

# Remove a variable
gcloud run services update "$SERVICE" --region="$REGION" \
  --remove-env-vars=LOG_LEVEL

# Many values: a YAML file of KEY: value pairs, kept in Git
gcloud run services update "$SERVICE" --region="$REGION" \
  --env-vars-file=env.prod.yaml

Values that contain commas (a list of origins, for example) need the alternate delimiter syntax (--set-env-vars="@ORIGINS=a.example,b.example@LOG_LEVEL=INFO") or, more cleanly, the --env-vars-file form. Reserved names such as PORT cannot be set. For a function, gcloud run deploy FUNCTION --source . --function ENTRY --base-image …​ takes the same --set-env-vars flag as any other service (the older gcloud functions deploy --set-env-vars form applies to first generation functions).

Environment variables are visible to anyone who can view the service, in the console, in gcloud run services describe and in revision exports, so they are for configuration, not secrets.

Secrets as environment variables or volumes

--set-secrets (replace all), --update-secrets (add or change) and --remove-secrets attach Secret Manager secrets. The two forms behave differently:

# As an environment variable: pin a version; resolved when an instance starts
gcloud run services update "$SERVICE" --region="$REGION" \
  --update-secrets=DB_PASSWORD=catalog-db-password:3

# As a volume (the file's directory is the mount, the file is the secret):
# each read returns the latest version
gcloud run services update "$SERVICE" --region="$REGION" \
  --update-secrets=/etc/secrets/db-password=catalog-db-password:latest

The service’s runtime service account needs roles/secretmanager.secretAccessor on the secret (granted on the secret, not the project). The mount path must contain the directory and the file name, two secrets cannot share a path, and mounting over an existing directory hides its contents. Cloud Run does not support regional secrets, so a service that needs one calls the Secret Manager API itself. For a rotating credential, prefer the volume: the next read of the file sees the new version with no redeploy, whereas an environment variable keeps the value read at instance start.

A Parameter Manager file on Cloud Run

Cloud Run cannot yet mount a Parameter Manager parameter as a volume (check the Cloud Run documentation, which is the authority on what a volume source can be). Two patterns cover the gap:

  • Render in the application at startup, with the Java snippet above. catalog-api is given only the parameter name and the pinned version as environment variables (SETTINGS_PARAMETER=bookshelf-settings, SETTINGS_VERSION=v1) and fetches the rest. Changing configuration is versions create v2 followed by gcloud run services update catalog-api --update-env-vars=SETTINGS_VERSION=v2, which is also the rollback point.

  • Render before the app starts in an entrypoint script or a sidecar container that writes /etc/config/settings.yaml into a shared in-memory volume, then lets Spring import it. The sidecar runs the gcloud parametermanager parameters versions render command or a small client; the shared volume is declared with --add-volume=name=config,type=in-memory and --add-volume-mount.

Both need roles/parametermanager.parameterAccessor on the parameter for the service account, and the parameter’s own identity needs access to the referenced secrets, as in the table above.

Kubernetes ConfigMaps on GKE

On GKE (Autopilot cluster bookshelf-gke in the Bookshelf scenario) configuration is the standard Kubernetes mechanism, documented once for all clusters on ConfigMaps and, for Docker-level orchestration concepts, Orchestration: Swarm Mode and Kubernetes. The Spring side of the same objects is the ConfigMap section of Configuration and Profiles. GKE specifics are about rollout, not the object.

A ConfigMap as environment variables and as a file

apiVersion: v1
kind: ConfigMap
metadata:
  name: orders-api-config
  namespace: bookshelf
data:
  LOG_LEVEL: INFO
  ORDERS_PAGE_SIZE: "50"
  settings.yaml: |
    orders:
      confirmationDelaySeconds: 5
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders-api
  namespace: bookshelf
spec:
  replicas: 2
  selector:
    matchLabels: { app: orders-api }
  template:
    metadata:
      labels: { app: orders-api }
      annotations:
        # Changes when the ConfigMap content changes; set by CI or Helm
        config-checksum: "REPLACE_WITH_SHA256_OF_CONFIGMAP"
    spec:
      containers:
        - name: orders-api
          image: us-central1-docker.pkg.dev/my-project-id/bookshelf/orders-api:1.4.0
          envFrom:
            - configMapRef:
                name: orders-api-config
          volumeMounts:
            - name: config
              mountPath: /etc/config
              readOnly: true
      volumes:
        - name: config
          configMap:
            name: orders-api-config
            items:
              - key: settings.yaml
                path: settings.yaml

Derived from the Kubernetes ConfigMaps page and the GKE ConfigMap concept page.

gcloud container clusters get-credentials bookshelf-gke --region=us-central1
kubectl apply -f orders-api-config.yaml
kubectl -n bookshelf get configmap orders-api-config -o yaml

What happens when the ConfigMap changes

Environment variables are read when a container starts. A changed ConfigMap does not reach running pods through envFrom; a mounted file is refreshed by the kubelet after a delay of up to a minute or so, except when mounted with subPath, which is never refreshed. The application must also notice the change (Spring reads files once unless it reloads). Three practical answers:

  • Restart on purpose: kubectl -n bookshelf rollout restart deployment/orders-api. Fine for manual changes.

  • Checksum annotation: a hash of the ConfigMap in the pod template (as above, or checksum/config set by Helm) makes any content change a new pod template, hence a rolling update, with the usual rollback (kubectl rollout undo). This is the recommended way to tie configuration to rollouts.

  • Hot reload: mount the file as a directory volume and have the application watch it; Spring Cloud Kubernetes can reload on ConfigMap change, covered on Configuration and Profiles.

On Autopilot a rolling restart briefly runs old and new pods side by side, so the extra requests count against your resource requests, and a PodDisruptionBudget protects availability during it; see Deploying Microservices on GKE.

Config Sync: one source of truth for many clusters

Config Sync is the GitOps component of GKE fleets. Since 2025-09-02 it is included in GKE at no additional charge (earlier it required a GKE Enterprise subscription), together with Policy Controller and the other fleet features. It watches a source of truth — a Git repository, an OCI image or a Helm chart — and continuously reconciles the cluster to match it, undoing manual drift. Two objects define what is watched: a RootSync (cluster-scoped objects and many namespaces, managed by platform admins) and a RepoSync (a single namespace, managed by the team that owns it). Use it for ConfigMaps that must be identical on every cluster of the fleet (feature switches, endpoints, quotas) and for the policies that go with them; do not use it for per-cluster secrets.

gcloud services enable gkehub.googleapis.com anthosconfigmanagement.googleapis.com

# Register the cluster in the project fleet (if it is not already), then enable the feature
gcloud container clusters update bookshelf-gke --region=us-central1 \
  --enable-fleet
gcloud beta container fleet config-management enable

Derived from Install Config Sync (the exact feature-enable and per-membership apply commands have changed across gcloud releases; follow the current page for yours).

apiVersion: configsync.gke.io/v1beta1
kind: RootSync
metadata:
  name: root-sync
  namespace: config-management-system
spec:
  sourceFormat: unstructured
  sourceType: git
  git:
    repo: https://github.com/example-org/bookshelf-config
    branch: main
    dir: clusters/prod
    auth: none

Derived from Config Sync overview. auth: none suits a public repository only; for a private one use a read-only token stored in a Kubernetes secret, a Secure Source Manager or GitHub app credential, or workload identity with Artifact Registry for an OCI source, as described in the installation page. The repository then holds orders-api-config.yaml under clusters/prod, and a commit is the change record: review in a pull request, merge, and Config Sync applies it. Pair the sync with the checksum annotation or a controller such as Reloader so the pods pick the change up.

Getting Parameter Manager and Secret Manager values into a ConfigMap

There is no native "sync a Parameter Manager parameter into a ConfigMap" controller at the check date. State it plainly and choose one of these:

  • Render at deploy time. The pipeline runs gcloud parametermanager parameters versions render, writes the result into the ConfigMap manifest or a Secret, and applies it (or commits it to the Config Sync repository for non-secret values only). Simple and auditable; the cluster never calls the parameter service.

  • An init container or Job that renders the version at pod start and writes a file into a shared emptyDir, using Workload Identity Federation for GKE and roles/parametermanager.parameterAccessor granted to the Kubernetes service account’s principal.

  • The GKE Secret Manager add-on (--enable-secret-manager) mounts Secret Manager secrets as files through the Secrets Store CSI driver and can sync them to Kubernetes Secrets; it covers secrets, not parameters. See Secret Manager and Cloud KMS. An External Secrets-style operator is the portable alternative.

Do not copy rendered secret values into a ConfigMap, which is not encrypted separately and is readable by anyone with get configmaps; secrets belong in Secret Manager or Kubernetes Secrets with application-layer encryption enabled.

Feature flags

A feature flag is configuration with a lifetime and an owner. Two Google-hosted options and one open standard:

  • Firebase Remote Config stores key-value parameters with conditions (percentage, country, app version, audience) and serves them to mobile and web clients; a server-side variant, the Remote Config API for the Admin SDK, serves backend code. It is the natural choice if the product already uses Firebase, and it is covered at the surface level here only. See Firebase Remote Config.

  • OpenFeature with flagd. OpenFeature is a vendor-neutral flag API with providers for many back ends; flagd is a small open-source flag daemon that reads flag definitions from a file, a ConfigMap or an HTTP source and streams changes. On GKE it runs as a Deployment or a sidecar and the flag file is a ConfigMap managed by Config Sync, which gives flags a Git history and review. See OpenFeature.

  • A homemade flag in a Parameter Manager version works for coarse switches (orders.newCheckout: false): read the rendered YAML on a timer and branch in code. It lacks targeting and gradual rollout; use it for kill switches, not experiments.

Whichever you choose, remove the flag when the rollout is complete; a flag that stays is permanent complexity.

The retired Runtime Configurator

Runtime Configurator was an older Google Cloud service that stored key-value configuration in hierarchical "configurations" with "waiter" resources to block a deployment until a value appeared. It belongs to Deployment Manager, whose end of support was 2026-04-01 (extended support for blockers until 2027-03-31) and whose shutdown is scheduled for 2027-06-30; the replacement for Deployment Manager is Infrastructure Manager (managed Terraform), covered on Infrastructure as Code. Older guides and some Cloud Functions tutorials still show gcloud beta runtime-config; do not start new work on it. Migrate to Parameter Manager for configuration values, to Secret Manager for secrets and to Pub/Sub or Cloud Workflows for the "wait until ready" role of waiters.

Precedence: which value wins

When several mechanisms define the same key, the application’s own rules decide, but the platform order is predictable and should be written down for each service.

Order (highest first) Cloud Run Spring Boot on GKE

1

Command-line arguments in the container args

Command-line arguments and SPRING_APPLICATION_JSON

2

Environment variables (including secret-backed ones)

OS environment variables, including envFrom ConfigMaps and Secrets

3

Files on mounted volumes (secret volume, in-memory config file) imported by the app

spring.config.import sources: mounted files, then rendered Parameter Manager YAML

4

Defaults in the image (application.yaml inside the jar)

Defaults in the image

Spring’s exact order, including profile-specific files, is on Configuration and Profiles. A rendered Parameter Manager file imported with spring.config.import sits below environment variables, which is what makes an emergency override possible without touching the parameter.

Security and networking

  • Least privilege per parameter. Grant parameterAccessor on one parameter to one service account, never on the project. Keep separate parameters per environment so a dev service account cannot render production configuration.

  • No secrets in plain configuration. Use REF references or Secret Manager; do not put credentials in parameters, ConfigMaps or Cloud Run environment variables. Detection tools commonly scan Git repositories, which is another reason to render from the service rather than committing.

  • Audit. Admin Activity audit logs record parameter and version changes by default; enable Data Access audit logs for Parameter Manager and Secret Manager to log who rendered a version and who read a secret.

  • Customer-managed keys. Parameter payloads are encrypted by Google by default; regional parameters can use CMEK. Encryption keys are covered on Secret Manager and Cloud KMS.

  • Network path. The API is a Google API; reach it from private VPCs through Private Google Access or Private Service Connect for Google APIs (see VPC Networking on Google Cloud). VPC Service Controls perimeters can include parametermanager.googleapis.com and secretmanager.googleapis.com.

  • Config Sync credentials. Prefer workload identity or short-lived tokens for private sources; a read-only deploy key is the minimum.

What changed recently, and what older guides still show

Date Change

2024-08-22

Cloud Functions 2nd generation renamed Cloud Run functions; configuration flags are the Cloud Run ones.

2025-03-27

Parameter Manager generally available.

2025-09-02

Config Sync (with fleets, Policy Controller and Connect Gateway) included in GKE with no extra charge.

2026-04-01

Deployment Manager, and with it Runtime Configurator, reached end of support; shutdown is scheduled for 2027-06-30.

Older guides still show: environment variables on Cloud Functions as the only configuration option, gcloud beta runtime-config for shared configuration, latest secret versions injected as environment variables in production, and Config Sync described as part of a paid Anthos subscription. The current approach is Parameter Manager plus Secret Manager references, pinned versions, and Config Sync as part of GKE.

Troubleshooting

Symptom Likely cause Fix

PERMISSION_DENIED when rendering a parameter

The caller lacks roles/parametermanager.parameterAccessor (the viewer role reads the raw payload only)

Grant the accessor role on the parameter to the runtime service account

Render fails or returns an error naming a secret

The parameter’s own principal identity cannot access the referenced secret, or the secret version is disabled

Bind secretAccessor on the secret to the principal://parametermanager…​ identity; enable the version

Reference text appears in the rendered output

Parameter format is UNFORMATTED, or the reference syntax is malformed

Use a YAML or JSON parameter and the exact REF("//secretmanager.googleapis.com/…​") form

Cloud Run revision still shows the old value

The variable was set on a different service or region, or traffic still points at the previous revision

Run gcloud run revisions list, check the traffic split, and send traffic to the new revision

Secret env var not updated after adding a secret version

Environment variables are read when the instance starts

Deploy a new revision, or use a volume for values that must rotate without a redeploy

Pod does not see the new ConfigMap value

Env vars are read at start; subPath mounts never refresh

Roll the deployment (checksum annotation or rollout restart) or mount without subPath

Config Sync shows STALLED or the ConfigMap keeps reverting

Invalid manifest in the repository, missing credentials, or someone edits the object by hand

Run kubectl get rootsync -n config-management-system -o yaml, read the error, fix Git, and stop manual edits

Startup slow or throttled by quota

Every instance renders the parameter at once

Cache the rendered value, add jitter, request a quota increase

Clean up

Remove what this page created, in dependency order, so nothing keeps billing or keeps access open:

# GKE: ConfigMap, then the Config Sync source (if you enabled it for this exercise)
kubectl -n bookshelf delete -f orders-api-config.yaml --ignore-not-found
kubectl -n config-management-system delete rootsync root-sync --ignore-not-found

# Cloud Run: drop the variables and secret attachments you added
gcloud run services update catalog-api --region=us-central1 \
  --remove-env-vars=CATALOG_PAGE_SIZE,LOG_LEVEL \
  --remove-secrets=DB_PASSWORD

# Parameter Manager: delete versions, then the parameter
gcloud parametermanager parameters versions delete v1 \
  --parameter=bookshelf-settings --location=global --quiet
gcloud parametermanager parameters delete bookshelf-settings \
  --location=global --quiet

# IAM bindings that referenced the parameter or its identity
gcloud secrets remove-iam-policy-binding catalog-db-password \
  --member="$PARAM_UID" --role="roles/secretmanager.secretAccessor"

Delete the secret catalog-db-password itself on Secret Manager and Cloud KMS (secret versions may be retained for the delayed-destruction period, if one is set). Disable Config Sync with the fleet feature commands if no other cluster uses it. For a throwaway project, deleting the project removes everything at once after the 30-day pending-deletion window.

References