{"id":495,"date":"2026-09-25T08:50:00","date_gmt":"2026-09-25T06:50:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/?p=495"},"modified":"2026-10-26T12:44:32","modified_gmt":"2026-10-26T11:44:32","slug":"serverless-microservices-scaling-on-google-cloud-run-with-github-actions","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/","title":{"rendered":"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions"},"content":{"rendered":"<p>Google Cloud Run hosts containerized web services without operating a server or Kubernetes cluster. With suitable settings, a service with no requests can scale to zero instances. Traffic increases the instance count within available quotas and scaling limits. An instance is a running copy of the application. Starting a new copy takes time; this delay is called a cold start. Application maintenance and charges for other services still matter.<\/p>\n<p>An image packages the application and the files needed to run it. A revision is a deployed version with a specific image and configuration. GitHub Actions can build images and deploy through Workload Identity Federation (WIF). WIF replaces a permanently stored Google service-account key with short-lived credentials. Compromised workflows, excessive permissions and accidentally bundled credentials remain risks. This example therefore builds before cloud authentication and initially deploys a revision without regular traffic.<\/p>\n<h2>1. Prerequisites and separate identities<\/h2>\n<p>The project, billing, required APIs, Artifact Registry repository <code>services<\/code>, deployer account and separate runtime account must already exist. The example updates an existing <code>api-service<\/code> in <code>us-central1<\/code>. The service has IAM invocation checks enabled and no public invocation grants. Initial provisioning and public-access changes require suitable administrative permissions outside this pipeline.<\/p>\n<ul><li><strong>Deployer:<\/strong> <code>ci-cd-deployer<\/code> needs Artifact Registry Writer on the image repository, Cloud Run Developer on the existing service and Service Account User on the runtime account. Writer also includes the image-reading permissions needed for deployment.<\/li><li><strong>Runtime account:<\/strong> <code>api-runtime<\/code> receives only application permissions, such as access to a specific datastore. Deployment permissions do not belong to this identity.<\/li><li><strong>Application:<\/strong> The container must listen on <code>0.0.0.0:$PORT<\/code> and keep sessions or persistent data outside the ephemeral container. A Dockerfile and an executable, project-specific <code>ci\/test.sh<\/code> are prerequisites.<\/li><\/ul>\n<figure class=\"lw-diagram\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/dia-495-review-20261024.png\" width=\"1120\" height=\"580\" alt=\"Image build before cloud authentication, deployment by image digest, followed by testing and release\"><figcaption>The build runs before the cloud credential file is created. WIF restricts cloud access; application tests and an explicit traffic switch complete the release.<\/figcaption><\/figure>\n<h2>2. WIF restrictions for the owner, repository and main branch<\/h2>\n<p>These commands establish a new trust relationship. All example identifiers need replacement beforehand. <code>PROJECT_NUMBER<\/code> is the numeric Google project number, not the project ID. <code>OWNER_ID<\/code> and <code>REPOSITORY_ID<\/code> are numeric GitHub identifiers. These avoid trusting a deleted organization or repository name that another account later reclaims.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"bash\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Shell<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-bash\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-comment\">#!\/usr\/bin\/env bash<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">set<\/span> <span class=\"cbb-attr\">-euo<\/span> pipefail\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"># Replace all example identifiers before administrative setup.<\/span>\n<\/span><span class=\"cbb-line\">PROJECT_ID=<span class=\"cbb-string\">\"enterprise-ai-project\"<\/span>\n<\/span><span class=\"cbb-line\">PROJECT_NUMBER=<span class=\"cbb-string\">\"1234567890\"<\/span>\n<\/span><span class=\"cbb-line\">OWNER_ID=<span class=\"cbb-string\">\"11111111\"<\/span>\n<\/span><span class=\"cbb-line\">REPOSITORY_ID=<span class=\"cbb-string\">\"22222222\"<\/span>\n<\/span><span class=\"cbb-line\">DEPLOYER=<span class=\"cbb-string\">\"ci-cd-deployer@<\/span><span class=\"cbb-variable\">${PROJECT_ID}<\/span><span class=\"cbb-string\">.iam.gserviceaccount.com\"<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">gcloud iam workload-identity-pools create github-actions-pool \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--project<\/span>=<span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$PROJECT_ID<\/span><span class=\"cbb-string\">\"<\/span> <span class=\"cbb-attr\">--location<\/span>=global \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--display-name<\/span>=<span class=\"cbb-string\">\"GitHub Actions Pool\"<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">gcloud iam workload-identity-pools providers create-oidc github-provider \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--project<\/span>=<span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$PROJECT_ID<\/span><span class=\"cbb-string\">\"<\/span> <span class=\"cbb-attr\">--location<\/span>=global \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--workload-identity-pool<\/span>=github-actions-pool \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--issuer-uri<\/span>=<span class=\"cbb-string\">\"https:\/\/token.actions.githubusercontent.com\"<\/span> \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--attribute-mapping<\/span>=<span class=\"cbb-string\">\"google.subject=assertion.sub,attribute.repository_id=assertion.repository_id,attribute.repository_owner_id=assertion.repository_owner_id,attribute.ref=assertion.ref,attribute.event_name=assertion.event_name\"<\/span> \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--attribute-condition<\/span>=<span class=\"cbb-string\">\"assertion.repository_owner_id == '<\/span><span class=\"cbb-variable\">${OWNER_ID}<\/span><span class=\"cbb-string\">' &amp;&amp; assertion.repository_id == '<\/span><span class=\"cbb-variable\">${REPOSITORY_ID}<\/span><span class=\"cbb-string\">' &amp;&amp; assertion.ref == 'refs\/heads\/main' &amp;&amp; assertion.event_name == 'push'\"<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">gcloud iam service-accounts add-iam-policy-binding <span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$DEPLOYER<\/span><span class=\"cbb-string\">\"<\/span> \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--project<\/span>=<span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$PROJECT_ID<\/span><span class=\"cbb-string\">\"<\/span> <span class=\"cbb-attr\">--role<\/span>=roles\/iam.workloadIdentityUser \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--member<\/span>=<span class=\"cbb-string\">\"principalSet:\/\/iam.googleapis.com\/projects\/<\/span><span class=\"cbb-variable\">${PROJECT_NUMBER}<\/span><span class=\"cbb-string\">\/locations\/global\/workloadIdentityPools\/github-actions-pool\/attribute.repository_id\/<\/span><span class=\"cbb-variable\">${REPOSITORY_ID}<\/span><span class=\"cbb-string\">\"<\/span><\/span><\/code><\/pre><\/figure>\n<p>The provider condition permits only push events from the specified repository on <code>main<\/code>. A workflow trigger alone would not enforce this restriction in Google Cloud. WIF and IAM changes can take time to propagate. The <code>roles\/iam.workloadIdentityUser<\/code> binding permits impersonation of the deployer account; resource permissions are still required separately.<\/p>\n<p>Branch protection and reviewed workflow changes remain essential: another eligible workflow on <code>main<\/code> can satisfy the same conditions. The GitHub <code>production<\/code> environment needs appropriate protection rules. Writing the environment name in YAML does not create an approval requirement.<\/p>\n<h2>3. Image build, authentication and revision staging<\/h2>\n<p>Before the first run, <code>gha-creds-*.json<\/code> belongs in <code>.gitignore<\/code>, with the following exclusions in <code>.dockerignore<\/code>. Additional secret files and Dockerfile-specific ignore files require project-specific handling; later exception rules must not re-include credentials.<\/p>\n<figure style=\"--cbb-digits:1\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"plain\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Text<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-plain\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\">gha-creds-*.json\n<\/span><span class=\"cbb-line\">.git\n<\/span><span class=\"cbb-line\">.env\n<\/span><span class=\"cbb-line\">.env.*<\/span><\/code><\/pre><\/figure>\n<p>The auth action writes a short-lived credential file into the workspace by default. A later <code>docker build<\/code> with a broad <code>COPY<\/code> could include this file in the image. Tests and image construction therefore run before cloud authentication. Action versions are pinned to verified commits; updates still require review.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"yaml\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">YAML<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-yaml\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-attr\">name<\/span>: Build and stage a Cloud Run revision\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-attr\">on<\/span>:\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">push<\/span>:\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">branches<\/span>: &#91;main&#93;\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-attr\">permissions<\/span>:\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">contents<\/span>: read\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">id-token<\/span>: write\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-attr\">concurrency<\/span>:\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">group<\/span>: cloud-run-api-service\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">cancel-in-progress<\/span>: <span class=\"cbb-constant\">false<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-attr\">env<\/span>:\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">PROJECT_ID<\/span>: enterprise-ai-project\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">REGION<\/span>: us-central1\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">IMAGE<\/span>: us-central1-docker.pkg.dev\/enterprise-ai-project\/services\/api-service\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">PROVIDER<\/span>: projects\/1234567890\/locations\/global\/workloadIdentityPools\/github-actions-pool\/providers\/github-provider\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">DEPLOYER<\/span>: ci-cd-deployer@enterprise-ai-project.iam.gserviceaccount.com\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">RUNTIME<\/span>: api-runtime@enterprise-ai-project.iam.gserviceaccount.com\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-attr\">jobs<\/span>:\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">stage<\/span>:\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">runs-on<\/span>: ubuntu-latest\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">timeout-minutes<\/span>: <span class=\"cbb-number\">30<\/span>\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">environment<\/span>: production\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">defaults<\/span>:\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-attr\">run<\/span>:\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">shell<\/span>: bash\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">steps<\/span>:\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> <span class=\"cbb-attr\">name<\/span>: Checkout\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">uses<\/span>: actions\/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 <span class=\"cbb-comment\"># v7<\/span>\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">with<\/span>:\n<\/span><span class=\"cbb-line\">          <span class=\"cbb-attr\">persist-credentials<\/span>: <span class=\"cbb-constant\">false<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> <span class=\"cbb-attr\">name<\/span>: Application tests and build before cloud authentication\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">run<\/span>: <span class=\"cbb-meta\">|<\/span>\n<\/span><span class=\"cbb-line\">          set -euo pipefail\n<\/span><span class=\"cbb-line\">          .\/ci\/test.sh\n<\/span><span class=\"cbb-line\">          docker build --tag <span class=\"cbb-string\">\"$IMAGE:$GITHUB_SHA\"<\/span> .\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> <span class=\"cbb-attr\">name<\/span>: Authenticate for image push\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">uses<\/span>: google-github-actions\/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 <span class=\"cbb-comment\"># v3<\/span>\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">with<\/span>:\n<\/span><span class=\"cbb-line\">          <span class=\"cbb-attr\">workload_identity_provider<\/span>: <span class=\"cbb-variable\">${{ env.PROVIDER }}<\/span>\n<\/span><span class=\"cbb-line\">          <span class=\"cbb-attr\">service_account<\/span>: <span class=\"cbb-variable\">${{ env.DEPLOYER }}<\/span>\n<\/span><span class=\"cbb-line\">          <span class=\"cbb-attr\">project_id<\/span>: <span class=\"cbb-variable\">${{ env.PROJECT_ID }}<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> <span class=\"cbb-attr\">name<\/span>: Set up gcloud\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">uses<\/span>: google-github-actions\/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db <span class=\"cbb-comment\"># v3<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> <span class=\"cbb-attr\">name<\/span>: Push image\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">run<\/span>: <span class=\"cbb-meta\">|<\/span>\n<\/span><span class=\"cbb-line\">          set -euo pipefail\n<\/span><span class=\"cbb-line\">          gcloud auth configure-docker <span class=\"cbb-string\">\"$REGION-docker.pkg.dev\"<\/span> --quiet\n<\/span><span class=\"cbb-line\">          docker push <span class=\"cbb-string\">\"$IMAGE:$GITHUB_SHA\"<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> <span class=\"cbb-attr\">name<\/span>: Refresh authentication before deployment\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">uses<\/span>: google-github-actions\/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 <span class=\"cbb-comment\"># v3<\/span>\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">with<\/span>:\n<\/span><span class=\"cbb-line\">          <span class=\"cbb-attr\">workload_identity_provider<\/span>: <span class=\"cbb-variable\">${{ env.PROVIDER }}<\/span>\n<\/span><span class=\"cbb-line\">          <span class=\"cbb-attr\">service_account<\/span>: <span class=\"cbb-variable\">${{ env.DEPLOYER }}<\/span>\n<\/span><span class=\"cbb-line\">          <span class=\"cbb-attr\">project_id<\/span>: <span class=\"cbb-variable\">${{ env.PROJECT_ID }}<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> <span class=\"cbb-attr\">name<\/span>: Configure refreshed gcloud credentials\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">uses<\/span>: google-github-actions\/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db <span class=\"cbb-comment\"># v3<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> <span class=\"cbb-attr\">name<\/span>: Stage revision without changing traffic\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">run<\/span>: <span class=\"cbb-meta\">|<\/span>\n<\/span><span class=\"cbb-line\">          set -euo pipefail\n<\/span><span class=\"cbb-line\">          gcloud run services describe api-service \\\n<\/span><span class=\"cbb-line\">            --project=<span class=\"cbb-string\">\"$PROJECT_ID\"<\/span> --region=<span class=\"cbb-string\">\"$REGION\"<\/span> &gt;\/dev\/null\n<\/span><span class=\"cbb-line\">          DIGEST=<span class=\"cbb-string\">\"$(gcloud artifacts docker images describe \"<\/span>$IMAGE:$GITHUB_SHA\" \\\n<\/span><span class=\"cbb-line\">            --project=<span class=\"cbb-string\">\"$PROJECT_ID\"<\/span> --format=<span class=\"cbb-string\">'value(image_summary.digest)'<\/span>)\"\n<\/span><span class=\"cbb-line\">          &#91;&#91; <span class=\"cbb-string\">\"$DIGEST\"<\/span> =~ ^sha256:&#91;0-9a-f&#93;{<span class=\"cbb-number\">64<\/span>}$ &#93;&#93;\n<\/span><span class=\"cbb-line\">          gcloud run deploy api-service \\\n<\/span><span class=\"cbb-line\">            --project=<span class=\"cbb-string\">\"$PROJECT_ID\"<\/span> --region=<span class=\"cbb-string\">\"$REGION\"<\/span> \\\n<\/span><span class=\"cbb-line\">            --image=<span class=\"cbb-string\">\"$IMAGE@$DIGEST\"<\/span> --service-account=<span class=\"cbb-string\">\"$RUNTIME\"<\/span> \\\n<\/span><span class=\"cbb-line\">            --no-traffic --tag=candidate \\\n<\/span><span class=\"cbb-line\">            --min-instances=0 --max-instances=50 \\\n<\/span><span class=\"cbb-line\">            --concurrency=80 --memory=512Mi --cpu=1 --cpu-throttling \\\n<\/span><span class=\"cbb-line\">            --quiet<\/span><\/code><\/pre><\/figure>\n<p>The pipeline pushes a commit-tagged image and deploys the resolved digest. A digest identifies image content; a tag alone can change. Authentication is renewed before deployment so build and push time do not unnecessarily consume the short authentication window. Very long uploads or deployments can still require fresh authentication and a controlled retry.<\/p>\n<p><code>--no-traffic<\/code> keeps regular traffic on previous revisions. The <code>candidate<\/code> tag creates a separate test URL and moves to the new revision on the next run. This URL still uses the service&#8217;s access rules. Smoke tests check essential application functions, such as a sample API request. These tests need an authorized caller, typically with Cloud Run Invoker and a suitable ID token. A passing startup check alone does not establish application correctness.<\/p>\n<p>After testing and checking the exact revision identifier, traffic can be moved explicitly. The placeholder below must become the actual tested revision. Rollback similarly selects an earlier verified revision. This does not undo database schema changes or external side effects.<\/p>\n<figure style=\"--cbb-digits:1\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"bash\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Shell<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-bash\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-comment\"># After authenticated smoke tests and approval of this exact revision:<\/span>\n<\/span><span class=\"cbb-line\">gcloud run services update-traffic api-service \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--project<\/span>=enterprise-ai-project <span class=\"cbb-attr\">--region<\/span>=us-central1 \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--to-revisions<\/span>=REVIEWED_REVISION_NAME=<span class=\"cbb-number\">100<\/span><\/span><\/code><\/pre><\/figure>\n<h2>4. Scaling and cost settings for the application<\/h2>\n<ul><li><strong>Concurrency 80:<\/strong> This is the example&#8217;s maximum simultaneous requests per instance, not a threshold that must first be filled. Autoscaling considers metrics including CPU and concurrency utilization. CPU-intensive or memory-heavy requests often need lower values; greater concurrency does not automatically reduce memory usage.<\/li><li><strong>Zero minimum instances:<\/strong> <code>--min-instances=0<\/code> applies to the new revision. Service-level minimum instances also need checking. With request-based billing, ordinary idle instances without minimum-instance retention incur no idle compute charges; startup, shutdown and requests can still be billed. Registry storage, networking, logs and GitHub Actions add costs.<\/li><li><strong>Maximum 50:<\/strong> <code>--max-instances=50<\/code> is a revision-level limit here. Multiple revisions and temporary overshoots can increase the total. A suitable service-level limit also helps protect dependencies; neither setting is a hard billing cap.<\/li><li><strong>Background work:<\/strong> <code>--cpu-throttling<\/code> selects request-based CPU allocation. Instance-based billing with continuously allocated CPU and minimum instances enables background work, but does not guarantee an uninterrupted process. Instances can terminate. Retryable work can use a durable queue with Cloud Tasks or appropriate Cloud Run jobs.<\/li><\/ul>\n<p>The values 80, 50 and 512 MiB are starting settings for this example. Load tests need to measure latency, error rate, memory use and database connections. Cloud Run can roll out revisions without planned downtime, but faulty code, incompatible migrations or exhausted quotas can still cause outages.<\/p>\n\n\n<!-- lw-flux-illu 495-a4 -->\n<figure class=\"lw-illu\"><img src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/illustrationen\/flux-495-a4.webp\" width=\"1120\" height=\"630\" loading=\"lazy\" decoding=\"async\" alt=\"Three folding tables each hold the same maximum number of plates, while a fourth leans folded against the wall. Likewise, concurrency sets how many requests one instance handles at once; unused ones cost nothing.\"><figcaption>Three folding tables each hold the same maximum number of plates, while a fourth leans folded against the wall. Likewise, concurrency sets how many requests one instance handles at once; unused ones cost nothing.<\/figcaption><\/figure>\n\n\n<div class=\"lw-faq\"><h2>Questions and answers<\/h2><h3>Is keyless deployment maintenance-free?<\/h3><p>No. WIF removes the permanently stored Google key from this workflow. Short-lived tokens, GitHub access and runtime permissions still need protection. Dependencies, base images, action commits and IAM rules require maintenance.<\/p><h3>Why is &#8211;allow-unauthenticated absent?<\/h3><p>The flag grants public invocation and requires additional IAM permissions. This example assumes an already private service and preserves invocation policy. Omitting the flag does not make an existing public service private.<\/p><h3>What still costs money after every instance stops?<\/h3><p>Stored images and other cloud services, among other resources. Registry cleanup should explicitly retain required release and rollback images. Scale-to-zero means neither free deployments nor free infrastructure.<\/p><\/div>\n<div class=\"lw-quellen\">\n<h2>Sources<\/h2>\n<ul>\n<li><a href=\"https:\/\/docs.cloud.google.com\/run\/docs\" target=\"_blank\" rel=\"noopener noreferrer\">Cloud Run documentation<\/a><\/li>\n<li><a href=\"https:\/\/docs.docker.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Docker documentation<\/a><\/li>\n<li><a href=\"https:\/\/docs.cloud.google.com\/iam\/docs\/workload-identity-federation-with-deployment-pipelines\" target=\"_blank\" rel=\"noopener noreferrer\">WIF for deployment pipelines<\/a><\/li><li><a href=\"https:\/\/github.com\/google-github-actions\/auth\/blob\/main\/docs\/TROUBLESHOOTING.md\" target=\"_blank\" rel=\"noopener noreferrer\">Auth action: credentials in build artifacts<\/a><\/li><li><a href=\"https:\/\/github.com\/google-github-actions\/auth\" target=\"_blank\" rel=\"noopener noreferrer\">Google Cloud authentication action<\/a><\/li><li><a href=\"https:\/\/docs.cloud.google.com\/run\/docs\/about-concurrency\" target=\"_blank\" rel=\"noopener noreferrer\">Cloud Run concurrency<\/a><\/li><li><a href=\"https:\/\/docs.cloud.google.com\/run\/docs\/configuring\/billing-settings\" target=\"_blank\" rel=\"noopener noreferrer\">Cloud Run billing settings<\/a><\/li><li><a href=\"https:\/\/docs.cloud.google.com\/run\/docs\/configuring\/max-instances-limits\" target=\"_blank\" rel=\"noopener noreferrer\">Maximum instance limits<\/a><\/li><li><a href=\"https:\/\/docs.cloud.google.com\/run\/docs\/rollouts-rollbacks-traffic-migration\" target=\"_blank\" rel=\"noopener noreferrer\">Testing revisions, traffic migration and rollback<\/a><\/li><li><a href=\"https:\/\/docs.cloud.google.com\/run\/docs\/reference\/iam\/roles\" target=\"_blank\" rel=\"noopener noreferrer\">Cloud Run deployment permissions<\/a><\/li><li><a href=\"https:\/\/docs.cloud.google.com\/run\/docs\/container-contract\" target=\"_blank\" rel=\"noopener noreferrer\">Cloud Run container runtime contract<\/a><\/li><li><a href=\"https:\/\/github.blog\/changelog\/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions\/\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub Actions commit pinning<\/a><\/li><\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>A technical step-by-step tutorial on deploying and scaling serverless microservices on Google Cloud Run using GitHub Actions and Workload Identity Federation.<\/p>\n","protected":false},"author":1,"featured_media":23096,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[92636],"tags":[91106,91144,91145,91407,91219],"class_list":["post-495","post","type-post","status-publish","format-standard","hentry","category-tutorials-en-cloud-ai","tag-automation","tag-devops","tag-docker","tag-google-cloud","tag-tutorial"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"Deploy Cloud Run with GitHub Actions: check Workload Identity Federation, deployment permissions, scaling, concurrency and costs.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Deploy Cloud Run with GitHub Actions: check Workload Identity Federation, deployment permissions, scaling, concurrency and costs.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-25T06:50:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-26T11:44:32+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/hero-495-review-20261024-dark.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions\",\"datePublished\":\"2026-09-25T06:50:00+00:00\",\"dateModified\":\"2026-10-26T11:44:32+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/\"},\"wordCount\":1084,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/hero-495-review-20261024-dark.png\",\"keywords\":[\"Automation\",\"DevOps\",\"Docker\",\"Google Cloud\",\"Tutorial\"],\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/\",\"name\":\"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/hero-495-review-20261024-dark.png\",\"datePublished\":\"2026-09-25T06:50:00+00:00\",\"dateModified\":\"2026-10-26T11:44:32+00:00\",\"description\":\"Deploy Cloud Run with GitHub Actions: check Workload Identity Federation, deployment permissions, scaling, concurrency and costs.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/hero-495-review-20261024-dark.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/hero-495-review-20261024-dark.png\",\"width\":1200,\"height\":630,\"caption\":\"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions | Lukas Wojcik","description":"Deploy Cloud Run with GitHub Actions: check Workload Identity Federation, deployment permissions, scaling, concurrency and costs.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/","og_locale":"en_US","og_type":"article","og_title":"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions | Lukas Wojcik","og_description":"Deploy Cloud Run with GitHub Actions: check Workload Identity Federation, deployment permissions, scaling, concurrency and costs.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-09-25T06:50:00+00:00","article_modified_time":"2026-10-26T11:44:32+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/hero-495-review-20261024-dark.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions","datePublished":"2026-09-25T06:50:00+00:00","dateModified":"2026-10-26T11:44:32+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/"},"wordCount":1084,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/hero-495-review-20261024-dark.png","keywords":["Automation","DevOps","Docker","Google Cloud","Tutorial"],"articleSection":["Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/","name":"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/hero-495-review-20261024-dark.png","datePublished":"2026-09-25T06:50:00+00:00","dateModified":"2026-10-26T11:44:32+00:00","description":"Deploy Cloud Run with GitHub Actions: check Workload Identity Federation, deployment permissions, scaling, concurrency and costs.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/hero-495-review-20261024-dark.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/hero-495-review-20261024-dark.png","width":1200,"height":630,"caption":"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/serverless-microservices-scaling-on-google-cloud-run-with-github-actions\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Serverless Microservices: Scaling on Google Cloud Run with GitHub Actions"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/495","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=495"}],"version-history":[{"count":8,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/495\/revisions"}],"predecessor-version":[{"id":27014,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/495\/revisions\/27014"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/23096"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=495"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=495"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=495"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}