gcpgrlx is a GCP-specific companion module for grlx that renders deployment recipes for shipping containerized gRPC and HTTP microservices to Google Cloud Run.
It is designed for teams that want to keep grlx as the automation layer while using Google Cloud as the runtime target.
- validates a microservice deployment spec
- resolves default Artifact Registry image URLs
- renders a
.grlxrecipe withcmd.runstates for:- enabling required GCP APIs
- ensuring an Artifact Registry repository exists
- deploying each service to Cloud Run
- applies gRPC-friendly defaults such as internal ingress, HTTP/2, and tighter concurrency
- supports advanced deployment controls like secrets, probes, rollout traffic, Cloud SQL, and revision settings
- can also render a companion Caddyfile for routing custom domains to Cloud Run services
- patches the deployment-time Caddyfile with live Cloud Run URLs after deploys finish
- exposes the renderer as both a Go package and a small CLI
The diagarm here showcases how gcpgrlx works with grlx to create configurations that can easily be used in the Google Cloud ecosystem.
The following showcases what would actually be created if you were to run the examples\microservices.yaml through the gcpgrlx cli and then the generated grlx configuration through the grlx cli.
Cloud Run is a strong default for microservices because it keeps the deployment contract small:
- each service is a container
- ingress, scaling, CPU, memory, and auth are first-class flags
- it maps cleanly onto generated
grlxcmd.runstates
For gRPC services, gcpgrlx can emit Cloud Run deploy commands with:
--use-http2- internal-only ingress by default
- disabled unauthenticated access by default
- service-level concurrency and optional VPC connector settings
- optional startup and liveness probes via
gcloud beta run deploy
go install .\cmd\gcpgrlxSee examples\microservices.yaml.
go run .\cmd\gcpgrlx render -f .\examples\microservices.yaml -out .\distThat writes:
dist\deploy.grlx
go run .\cmd\gcpgrlx render-caddy -f .\examples\microservices.yaml -out .\distThat writes:
dist\caddy\Caddyfile
Or print the generated Caddyfile directly:
go run .\cmd\gcpgrlx render-caddy -f .\examples\microservices.yaml --stdoutOnce your grlx CLI is connected to a farmer and your target sprout or cohort is registered, you can cook the generated recipe directly.
Preview the recipe without applying changes:
grlx cook .\dist\deploy.grlx -T gcp-runner --testApply the deployment recipe to a target sprout:
grlx cook .\dist\deploy.grlx -T gcp-runnerOr target a cohort instead of a single sprout:
grlx cook .\dist\deploy.grlx -C platformThis is the intended workflow: gcpgrlx renders the Cloud Run deployment recipe, and grlx distributes and executes that recipe against the machines that have gcloud and the required Google Cloud credentials.
When caddy.enabled: true is set, the generated deploy recipe also includes Caddy lifecycle steps: install Caddy on the target, query each Cloud Run service URL with gcloud run services describe, write the final Caddyfile into deployment_root, copy it into /etc/caddy/Caddyfile, validate it, and reload the Caddy service.
When smoke_tests are configured, the generated recipe appends end-to-end verification steps after deploy and Caddy apply work. HTTP smoke tests can target a fixed url or a named service; service-based tests automatically use the Caddy domain/path when available, otherwise they query the live Cloud Run URL directly.
go run .\cmd\gcpgrlx render-stdout -f .\examples\microservices.yamlgo run .\cmd\gcpgrlx plan -f .\examples\microservices.yamlgo run .\cmd\gcpgrlx validate -f .\examples\microservices.yamlgo run .\cmd\gcpgrlx init -out .\microservices.yamlTo print the starter config instead of writing a file:
go run .\cmd\gcpgrlx init --stdoutThe generated recipe includes states like:
- verify
gcloudis installed - enable
run.googleapis.comandartifactregistry.googleapis.com - create the Artifact Registry repository if missing
- deploy each microservice with
gcloud run deploy - deploy worker and cron jobs with
gcloud run jobs deploy - configure gRPC services with end-to-end HTTP/2 support
- install and apply Caddy when
caddy.enabled: true - run configured smoke tests at the end of the rollout
package main
import (
"fmt"
"os"
"github.com/djburkhart/gcpgrlx"
)
func main() {
raw, err := os.ReadFile("microservices.yaml")
if err != nil {
panic(err)
}
cfg, err := gcpgrlx.ParseConfig(raw)
if err != nil {
panic(err)
}
recipe, err := gcpgrlx.RenderRecipe(cfg)
if err != nil {
panic(err)
}
fmt.Println(recipe)
}Top-level fields:
project_idregionartifact_registry_repositorydeployment_root(optional)caddy(optional)required_services(optional)smoke_tests(optional)services
Top-level caddy fields:
enabledfile(optional output path, defaults toCaddyfile)template(optional inlinetext/templatefor advanced Caddyfile rendering)snippets(optional reusable named Caddy snippet bodies)
Top-level smoke_tests fields:
nameservice(optional named service target)type(httporcommand)url(optional explicit URL target)path(optional request path for HTTP tests)method(optional HTTP method, defaults toGET)headers(optional request headers)expected_status(optional, defaults to200)body_contains(optional response substring check)command(required fortype: command)timeout(optional, defaults to2m)skip_tls_verify(optional)
Per-service fields:
nameimage(optional; default Artifact Registry URL is generated when omitted)profile(service,worker, orcron; defaults toservice)service_account(optional)protocol(httporgrpc)commandargsportcpumemoryconcurrencymin_instancesmax_instancestimeouttasksparallelismmax_retriesrevision_suffixtraffic_percentno_trafficcpu_throttlingstartup_cpu_boostexecution_environmentuse_http2allow_unauthenticatedingressvpc_connectorvpc_egresscloud_sql_instancessecretsstartup_probeliveness_probeenvlabelsannotationscaddycron
Per-service caddy fields:
domainpath(optional, defaults to/)upstream(optional explicit override)headers(optional response headers)presets(optional built-in middleware preset imports)snippets(optional list of reusable snippet imports)cohorts(optional alias for additional snippet imports)
Per-service cron fields:
scheduletime_zone(optional, defaults toUTC)service_account(optional; defaults to the serviceservice_account)job_name(optional; defaults to{service-name}-schedule)
If protocol: grpc is set for a service, gcpgrlx automatically defaults:
ingress: internalallow_unauthenticated: falseuse_http2: trueconcurrency: 20
secretsrender to--update-secretscloud_sql_instancesrender to--add-cloudsql-instancestraffic_percentadds a follow-upgcloud run services update-trafficstepno_traffic: truekeeps a new revision dark after deploycommandandargsoverride container startup behaviorcpu_throttling,startup_cpu_boost, andexecution_environmentcontrol runtime behaviorstartup_probeandliveness_probeswitch recipe generation togcloud beta run deploy
profile: servicekeeps the current Cloud Run service flow with traffic, ingress, and optional Caddy routingprofile: workerrenders a Cloud Run Job deploy for queue consumers and one-off worker processesprofile: cronrenders a Cloud Run Job deploy plus a Cloud Scheduler HTTP job that triggers:runon a schedule- cron profiles automatically add
cloudscheduler.googleapis.comto the required service enablement list - worker and cron profiles do not support traffic splitting, Caddy routing, or HTTP smoke tests by service name
If top-level caddy.enabled: true is set, any service with a caddy block is included in the generated Caddyfile.
- routes are grouped by
domain pathcan split one domain across multiple servicesdomainis required for every service-levelcaddyblock when Caddy generation is enabledupstreamdefaults tohttps://{service-name}-{region}.a.run.app- during deploy recipes, unset upstreams are patched with the live
status.urlreturned by Cloud Run after deployment - deploy recipes can install Caddy with the distro package manager, copy the generated config to
/etc/caddy/Caddyfile, validate it, and reload the service - set
upstreamexplicitly if you want to pin a custom domain or a known upstream instead of using the live Cloud Run URL - top-level
snippetslet you define reusable Caddy blocks and each service can import built-inpresetsplus customsnippetsandcohorts templatelets you override the default Caddyfile layout with Gotext/template- duplicate
domain+pathcombinations are rejected during validation
Built-in caddy.presets names:
compressionsecurity-headershstscors-permissiveno-store
These render as reusable named imports, so presets and custom snippets can be mixed on the same service.
Custom caddy.template values receive:
.Configfor the parsedConfig.Domainsfor the sorted domains and their routes.Snippetsfor named reusable snippet bodies
Available template helpers:
indent STRING PREFIXjoin SLICE SEPquote STRINGtrim STRING
- service-based HTTP smoke tests use the Caddy edge route when the referenced service has a
caddyblock - otherwise they query the live Cloud Run
status.urlbefore issuing the request - command smoke tests let you run custom checks like
grpcurl, schema checks, or multi-step shell probes - smoke test steps run after deploy, traffic, and Caddy lifecycle steps so they exercise the final routed system
go test .\...MIT

