Semaphore sponsored this post, which has been brought to you by the Semaphore CI/CD platform.

Google has launched Cloud Run, a new solution for running serverless applications based on Docker containers, this week at its at its Cloud Next ’19 conference. What we can say now is this is an important step for serverless computing — deploying to Cloud Run is much easier than running containers on Kubernetes. It also has no architectural restrictions, which Lambda functions do.

What Is Google Cloud Run?

Marko Anastasov Marko is a software developer and cofounder of Semaphore, the CI/CD platform powering some of the world's best engineering teams. He writes about practices and tools that support continuous improvement.

Google Cloud Run is a fully managed platform that takes a Docker container image and runs it as a stateless, autoscaling HTTP service.

The difference between Cloud Run and the first- generation of serverless platforms — such as AWS Lambda, Google Cloud functions or Azure functions — is that it allows you to run arbitrary applications serving multiple endpoints, not small functions with a specific interface.

Cloud Run is based on Knative, which means that similar solutions will likely show up on other managed Kubernetes platforms.

Will My Project Run on Google Cloud Run?

Google has published a Container runtime contract, which lists the requirements for containers, including:

The container is compiled for 64-bit Linux;

The container listens for HTTP requests on port 8080;

Can fit in up to 2GB of memory;

Container instances must start an HTTP server within four minutes after receiving a request;

Your application should work as containers are auto-scaled from 0 to multiple running instances;

All computation is stateless and scoped to a request.

As long your project adheres to the general requirements above, you can run any application written in any programming language on Cloud Run.

Note that Cloud Run is currently in beta and so these requirements may change over time.

There Is No Workflow — And That’s a Good Thing

Developers already familiar with Docker or traditional PaaS solutions like Heroku will feel right at home with Cloud Run.

Once your application is packaged in Docker, all it takes is to:

Push a container image to Google Container Registry;

Run gcloud beta run deploy.

Within minutes, Cloud Run will provision a new app under a domain which you can customize and make public.

Example: Continuous Deployment with Semaphore

In the following demo we will configure a serverless CI/CD pipeline with Semaphore for a microservice which will perform the following tasks:

Run automated tests;

Build a Docker container;

Push a container image to Google Container Registry;

Provide one-click manual deployment to a staging Cloud Run environment;

Automatically deploy to a production Cloud Run environment, after every successful build on the master Git branch.

You can find the complete source code of the project on GitHub.

Enabling Cloud Run

The official quick start guide by Google provides a roadmap for getting started with Cloud Run.

The first steps are to:

Enable the Cloud Run API on your account;

Install the Google Cloud SDK;

Install beta components with gcloud components install beta, or update them if you have installed them earlier with gcloud components update.

Dockerizing Your Application

In our example we will use a simple Sinatra web app packaged with the following Dockerfile:

FROM ruby:2.5 RUN apt-get update -qq && apt-get install -y build-essential ENV APP_HOME /app RUN mkdir $APP_HOME WORKDIR $APP_HOME ADD Gemfile* $APP_HOME/ RUN bundle install --without development test ADD . $APP_HOME EXPOSE 8080 CMD ["bundle", "exec", "rackup", "--host", "0.0.0.0", "-p", "8080"] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 FROM ruby : 2.5 RUN apt - get update - qq & amp ; & amp ; apt - get install - y build - essential ENV APP_HOME / app RUN mkdir $ APP_HOME WORKDIR $ APP_HOME ADD Gemfile* $ APP_HOME / RUN bundle install -- without development test ADD . $ APP_HOME EXPOSE 8080 CMD [ "bundle" , "exec" , "rackup" , "--host" , "0.0.0.0" , "-p" , "8080" ]

When adapting your existing Dockerfile, making sure that the application runs on port 8080 is probably going to be the only change that you need to make. If you don’t do that, you may see an error like:

Authenticating with Google Cloud and Container Registry (GCR)

In order to automate pushing Docker images to GCR in the CI/CD pipeline, Semaphore needs to authenticate with Google Cloud. To do that securely, we need to create a Semaphore secret based on a Google Cloud service account’s authentication key.

Once you have obtained your authentication key, upload it on Semaphore as a secret using the Semaphore CLI. The secret should define a file, let’s call it ‌.secrets.gcp.json:

sem create secret google-cloud-stg --file ~/Downloads/account-name-27f3a5bcea2d.json:.secrets.gcp.json 1 sem create secret google - cloud - stg -- file ~ / Downloads / account - name - 27f3a5bcea2d.json : . secrets . gcp . json

Defining the Delivery Pipelines

We can now write a Semaphore pipeline which builds, tags and pushes a Docker container to GCR:

# .semaphore/docker-build.yml # This pipeline runs after semaphore.yml version: v1.0 name: Docker build agent: machine: # Use a machine type with more RAM and CPU power for faster container # builds: type: e1-standard-4 os_image: ubuntu1804 blocks: - name: Build task: # Mount a secret which defines an authentication key file. # For info on creating secrets, see: # - https://docs.semaphoreci.com/article/66-environment-variables-and-secrets # - https://docs.semaphoreci.com/article/72-google-container-registry-gcr secrets: - name: google-cloud-stg jobs: - name: Docker build commands: # Authenticate using the file injected from the secret - gcloud auth activate-service-account --key-file=.secrets.gcp.json # Configure access to container registry, silence confirmation prompts with -q - gcloud auth configure-docker -q - checkout # Tag your images with gcr.io/ACCOUNT_PROJECT_NAME/SERVICE_NAME pattern # Use Git SHA to produce unique artifacts - docker build -t "gcr.io/semaphore2-stg/semaphore-demo-cloud-run:${SEMAPHORE_GIT_SHA:0:7}" . - docker push "gcr.io/semaphore2-stg/semaphore-demo-cloud-run:${SEMAPHORE_GIT_SHA:0:7}" promotions: # Deployment to staging can be trigger manually: - name: Deploy to staging pipeline_file: deploy-staging.yml # Automatically deploy to production on successful builds on master branch: - name: Deploy to production pipeline_file: deploy-production.yml auto_promote_on: - result: passed branch: - master 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 # .semaphore/docker-build.yml # This pipeline runs after semaphore.yml version : v1 . 0 name : Docker build agent : machine : # Use a machine type with more RAM and CPU power for faster container # builds: type : e1 - standard - 4 os_image : ubuntu1804 blocks : - name : Build task : # Mount a secret which defines an authentication key file. # For info on creating secrets, see: # - https://docs.semaphoreci.com/article/66-environment-variables-and-secrets # - https://docs.semaphoreci.com/article/72-google-container-registry-gcr secrets : - name : google - cloud - stg jobs : - name : Docker build commands : # Authenticate using the file injected from the secret - gcloud auth activate - service - account -- key - file = . secrets . gcp . json # Configure access to container registry, silence confirmation prompts with -q - gcloud auth configure - docker - q - checkout # Tag your images with gcr.io/ACCOUNT_PROJECT_NAME/SERVICE_NAME pattern # Use Git SHA to produce unique artifacts - docker build - t "gcr.io/semaphore2-stg/semaphore-demo-cloud-run:${SEMAPHORE_GIT_SHA:0:7}" . - docker push "gcr.io/semaphore2-stg/semaphore-demo-cloud-run:${SEMAPHORE_GIT_SHA:0:7}" promotions : # Deployment to staging can be trigger manually: - name : Deploy to staging pipeline_file : deploy - staging . yml # Automatically deploy to production on successful builds on master branch: - name : Deploy to production pipeline_file : deploy - production . yml auto_promote_on : - result : passed branch : - master

The pipelines defined in deploy-staging.yml and deploy-production.yml run the same steps, with the difference being in the name of the service.

Here’s how the production deployment runs:

# .semaphore/deploy-production.yml # This pipeline runs after docker-build.yml version: v1.0 name: Deploy to production agent: machine: type: e1-standard-2 os_image: ubuntu1804 blocks: - name: Deploy to production task: secrets: - name: google-cloud-stg jobs: - name: run deploy commands: - gcloud auth activate-service-account --key-file=.secrets.gcp.json - gcloud auth configure-docker -q # Deploy to Cloud Run, using flags to avoid interactive prompt # See https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy - gcloud beta run deploy markoci-demo-cloud-run --project semaphore2-stg --image gcr.io/semaphore2-stg/markoci-demo-cloud-run:${SEMAPHORE_GIT_SHA:0:7} --region us-central1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # .semaphore/deploy-production.yml # This pipeline runs after docker-build.yml version : v1 . 0 name : Deploy to production agent : machine : type : e1 - standard - 2 os_image : ubuntu1804 blocks : - name : Deploy to production task : secrets : - name : google - cloud - stg jobs : - name : run deploy commands : - gcloud auth activate - service - account -- key - file = . secrets . gcp . json - gcloud auth configure - docker - q # Deploy to Cloud Run, using flags to avoid interactive prompt # See https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy - gcloud beta run deploy markoci - demo - cloud - run -- project semaphore2 - stg -- image gcr . io / semaphore2 - stg / markoci - demo - cloud - run : $ { SEMAPHORE_GIT_SHA : 0 : 7 } -- region us - central1

Going Live

The last line of the deploy log in your local terminal or Semaphore job will contain the URL on which your new app is live, for example:

https://semaphore-demo-cloud-run-ud2bmvsmda-uc.a.run.app. 1 https : //semaphore-demo-cloud-run-ud2bmvsmda-uc.a.run.app.

When you open the URL for the first time, you will see:

This is because there’s one more step to make, and that is to make your service public in Google Cloud Run console. And voilà:

Wrapping up

Hopefully, this article has inspired you to build and ship something to Google Cloud Run with a well-oiled CI/CD pipeline. The next move is on you.