When you are working with an architecture that includes Kubernetes clusters you might still find useful to use Cloud Run for certain applications, like a web frontend, API gateway and more. At the same time, you may find confusing how to integrate it seamlessly in your CI/CD workflow.
gcloud CLI can deploy Cloud Run service, but it doesn’t have all possible deployment options, and in this case you can’t store configurations in a repository like a pre-configured manifest, or use the same Config Map with environment variables for both Kubernetes and Cloud Run applications. Luckily, it’s possible to deploy Cloud Run applications in a similar way as Kubernetes and I’m going to show how to do it.
Creating Cloud Run service
Cloud Run uses knative and you can find there a description for a base manifest structure. At the same time, I wasn’t be able to find a complete manifest reference for Cloud Run. But it isn’t a problem, because we can easily get a manifest preset from a Cloud Run service created with Console (a web interface):
- Go to Cloud Run Console
- Click “Create Service”.
- Set your preferable settings.
- Click “Create”.
Or from Cloud Run service created by gcloud CLI:
gcloud run deploy
Exporting Cloud Run YAML manifest
Our Cloud Run application is deployed, now we need to obtain YAML manifest. An easy way to do it by using gcloud CLI:
gcloud run services describe <cloudrun-service-name> --format=export > cloudrun-preset.yaml
This is how your exported Cloud Run YAML may look like:
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
annotations:
client.knative.dev/user-image: <region>-docker.pkg.dev/<project-name>/<container-name>@sha256:<hash>
run.googleapis.com/ingress: all
run.googleapis.com/ingress-status: all
labels:
cloud.googleapis.com/location: <region>
name: <app-name>
namespace: '<namespace>'
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/maxScale: '3'
run.googleapis.com/client-name: cloud-console
run.googleapis.com/cpu-throttling: 'true'
run.googleapis.com/execution-environment: gen1
run.googleapis.com/startup-cpu-boost: 'true'
name: <app-name>-<revision-code>
spec:
containerConcurrency: 80
containers:
- env:
- name: LISTEN_ADDR
value: 0.0.0.0
- name: LISTEN_PORT
value: '80'
- name: DB_HOST
value: 198.51.100.1
- name: DB_PORT
value: '5432'
- name: DB_NAME
value: db_default
- name: DB_SECRET
value: default-user
image: <region>-docker.pkg.dev/<project-name>/<container-name>@sha256:<hash>
ports:
- containerPort: 80
name: http1
resources:
limits:
cpu: 1000m
memory: 512Mi
serviceAccountName: compute@developer.gserviceaccount.com
timeoutSeconds: 300
traffic:
- latestRevision: true
percent: 100
Now we can adjust the preset by changing or removing certain fields and values. Then, the manifest can be committed to a git repository or put to any other place where you store your Kubernetes YAML manifests.
Deploying Cloud Run using YAML manifest
One of the ways to deploy Cloud Run instance from a manifest preset is by using yq and gcloud.
Let’s say we have configmap.yaml
with environment variables:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
data:
LISTEN_ADDR: 0.0.0.0
LISTEN_PORT: '80'
DB_HOST: 198.51.100.1
DB_PORT: '5432'
DB_NAME: db_default
DB_SECRET: default-user
A new container that we want to deploy is ${_DOCKER_IMAGE_URL}
with a digest ${_DOCKER_IMAGE_DIGEST}
The Bash deployment code may look like:
yq e ".spec.template.spec.containers[0].env = $(yq e -o=j -I=0 '.data | \
to_entries | (.[] |= with_entries( (select(.key=="key") | .key) = "name" \
) )' configmap.yaml)" cloudrun-preset.yaml > deployment.yaml;
artifact="${_DOCKER_IMAGE_URL}${_DOCKER_IMAGE_DIGEST}";
artifact=$artifact yq e -i \
'.metadata.annotations."client.knative.dev/user-image"=strenv(artifact)' \
deployment.yaml;
artifact=$artifact yq e -i \
'.spec.template.spec.containers[0].image=strenv(artifact)' \
deployment.yaml;
gcloud run services replace deployment.yaml;
Optionally, after running this script you can check if the deployment was successful, then you can commit deployment.yaml
to the repository where successful deployments are stored.
Now you can deploy the same application to Kubernetes and Cloud Run seamlessly inside the single CI/CD workflow.