Quickstart: Build and Deploy

This page shows you how to create a simple Hello World application, package it into a container image, upload the container image to Container Registry, and then deploy the container image to Cloud Run. The sample is shown in several languages, but note that you can use other languages in addition to the ones shown.

You can also follow this quickstart with a demo account on Qwiklabs.

Before you begin

  1. Sign in to your Google Account.

    If you don't already have one, sign up for a new account.

  2. Select or create a GCP project.

    Go to the project selector page

  3. Make sure that billing is enabled for your Google Cloud Platform project.

    Learn how to enable billing

  4. Enable the Cloud Build and Cloud Run APIs.

    Enable the APIs

  5. Install and initialize the Cloud SDK.
  6. Install the gcloud beta component:
    gcloud components install beta
  7. Update components:
    gcloud components update

Writing the sample application

For instructions on creating a sample hello world application that runs on Cloud Run, click the tab for your language:

Go

  1. Create a new directory named helloworld-go and change directory into it:

    mkdir helloworld-go
    cd helloworld-go
    
  2. Create a new file named helloworld.go and paste the following code into it:

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	log.Print("Hello world received a request.")
    	target := os.Getenv("TARGET")
    	if target == "" {
    		target = "World"
    	}
    	fmt.Fprintf(w, "Hello %s!\n", target)
    }
    
    func main() {
    	log.Print("Hello world sample started.")
    
    	http.HandleFunc("/", handler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    

    This code creates a basic web server that listens on the port defined by the PORT environment variable.

Your app is finished and ready to be containerized and uploaded to Container Registry.

Node.js

  1. Create a new directory named helloworld-nodejs and change directory into it:

    mkdir helloworld-nodejs
    cd helloworld-nodejs
    
  2. Create a package.json file with the following contents:

    {
      "name": "knative-serving-helloworld",
      "version": "1.0.0",
      "description": "Simple hello world sample in Node",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "author": "",
      "license": "Apache-2.0",
      "dependencies": {
        "express": "^4.16.4"
      }
    }
    
  3. In the same directory, create a index.js file, and copy the following lines into it:

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
      console.log('Hello world received a request.');
    
      const target = process.env.TARGET || 'World';
      res.send(`Hello ${target}!`);
    });
    
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log('Hello world listening on port', port);
    });
    

    This code creates a basic web server that listens on the port defined by the PORT environment variable.

Your app is finished and ready to be containerized and uploaded to Container Registry.

Python

  1. Create a new directory named helloworld-python and change directory into it:

    mkdir helloworld-python
    cd helloworld-python
    
  2. Create a file named app.py and paste the following code into it:

    import os
    
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        target = os.environ.get('TARGET', 'World')
        return 'Hello {}!\n'.format(target)
    
    if __name__ == "__main__":
        app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT', 8080)))
    

    This code creates a basic web server that listens on the port defined by the PORT environment variable.

Your app is finished and ready to be containerized and uploaded to Container Registry.

Java

Create a Spring Boot application.

  1. From the console, create a new empty web project using the CURL and unzip commands:

    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d javaVersion=1.8 \
        -d bootVersion=2.1.3.RELEASE \
        -d name=helloworld \
        -d artifactId=helloworld \
        -d baseDir=helloworld \
        -o helloworld.zip
    unzip helloworld.zip
    cd helloworld
    

    This creates a Spring Boot project.

  2. Update the HelloworldApplication class in src/main/java/com/example/helloworld/HelloworldApplication.java by adding a @RestController to handle the / mapping and also add a @Value field to provide the TARGET environment variable:

    package com.example.helloworld;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    public class HelloworldApplication {
    
    	@Value("${TARGET:World}")
    	String target;
    
    	@RestController
    	class HelloworldController {
    		@GetMapping("/")
    		String hello() {
    			return "Hello " + target + "!";
    		}
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(HelloworldApplication.class, args);
    	}
    }
    

    This code creates a basic web server that listens on the port defined by the PORT environment variable.

Your app is finished and ready to be containerized and uploaded to Container Registry.

To deploy Java to Cloud Run with other frameworks, review the Knative samples for Spark and Vert.x.

C#

  1. Install .NET Core SDK 2.2. Note that we only need to do this to create the new web project in the next step: the Dockerfile, which is described later, will load all dependencies into the container.

  2. From the console, create a new empty web project using the dotnet command:

    dotnet new web -o helloworld-csharp
    
  3. Change directory to helloworld-csharp.

  4. Update the CreateWebHostBuilder definition in Program.cs to listen on the port defined by the PORT environment variable:

    using System;
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    
    namespace helloworld_csharp
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateWebHostBuilder(args).Build().Run();
            }
    
            public static IWebHostBuilder CreateWebHostBuilder(string[] args)
            {
                string port = Environment.GetEnvironmentVariable("PORT") ?? "8080";
                string url = String.Concat("http://0.0.0.0:", port);
    
                return WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>().UseUrls(url);
            }
        }
    }
    

    This code creates a basic web server that listens on the port defined by the PORT environment variable.

Your app is finished and ready to be containerized and uploaded to Container Registry.

PHP

  1. Create a new directory named helloworld-php and change directory into it:

    mkdir helloworld-php
    cd helloworld-php
    
  2. Create a file named index.php and paste the following code into it:

    <?php
    $target = getenv('TARGET', true) ?: 'World';
    echo sprintf("Hello %s!", $target);
    

    This code creates a basic web server that listens on the port defined by the PORT environment variable.

Your app is finished and ready to be containerized and uploaded to Container Registry.

Ruby

  1. Create a new directory named helloworld-ruby and change directory into it:

    mkdir helloworld-ruby
    cd helloworld-ruby
    
  2. Create a file named app.rb and paste the following code into it:

    require 'sinatra'
    
    set :bind, '0.0.0.0'
    
    get '/' do
      target = ENV['TARGET'] || 'World'
      "Hello #{target}!\n"
    end
    

    This code creates a basic web server that listens on the port defined by the PORT environment variable.

  3. Create a file nameGemfile and copy the following into it:

    source 'https://rubygems.org'
    
    gem 'sinatra'
    gem 'rack', '>= 2.0.6'
    
  4. If you don't have Bundler installed, install Bundler.

  5. Generate a Gemfile.lock file by running:

    bundle install

Your app is finished and ready to be containerized and uploaded to Container Registry.

Shell

  1. Create a new directory named helloworld-shell and change directory into it:

    mkdir helloworld-shell
    cd helloworld-shell
    
  2. Create a script.sh file with the following contents:

    #!/bin/sh
    echo Hello ${TARGET:=World}!
    
    
    

    In order to execute this shell script on every incoming requests, this sample uses a small Go program that starts a basic web server and listen on the port defined by the PORT environment variable.

  3. Create a invoke.go file with the following contents:

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    	"os/exec"
    )
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	cmd := exec.CommandContext(r.Context(), "/bin/sh", "script.sh")
    	cmd.Stderr = os.Stderr
    	out, err := cmd.Output()
    	if err != nil {
    		w.WriteHeader(500)
    	}
    	w.Write(out)
    }
    
    func main() {
    	http.HandleFunc("/", handler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    

Your app is finished and ready to be containerized and uploaded to Container Registry.

Other

Cloud Run supports most languages. For simple samples in languages other than the ones in this table, see the following:

However, in all of these samples, ignore and omit the material about service.yaml and Docker Hub, because Cloud Run does not use these.

Containerizing an app and uploading it to Container Registry

To containerize the sample app, create a new file named Dockerfile in the same directory as the source files, and copy the following content:

Go

# Use the offical Golang image to create a build artifact.
# This is based on Debian and sets the GOPATH to /go.
# https://hub.docker.com/_/golang
FROM golang:1.12 as builder

# Copy local code to the container image.
WORKDIR /go/src/github.com/knative/docs/helloworld
COPY . .

# Build the command inside the container.
# (You may fetch or manage dependencies here,
# either manually or with a tool like "godep".)
RUN CGO_ENABLED=0 GOOS=linux go build -v -o helloworld

# Use a Docker multi-stage build to create a lean production image.
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM alpine
RUN apk add --no-cache ca-certificates

# Copy the binary to the production image from the builder stage.
COPY --from=builder /go/src/github.com/knative/docs/helloworld/helloworld /helloworld

# Run the web service on container startup.
CMD ["/helloworld"]

Node.js

# Use the official Node.js 10 image.
# https://hub.docker.com/_/node
FROM node:10

# Create and change to the app directory.
WORKDIR /usr/src/app

# Copy application dependency manifests to the container image.
# A wildcard is used to ensure both package.json AND package-lock.json are copied.
# Copying this separately prevents re-running npm install on every code change.
COPY package*.json ./

# Install production dependencies.
RUN npm install --only=production

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
CMD [ "npm", "start" ]

Add a further .dockerignore file to ensure local files do not affect the container build process:

Dockerfile
README.md
node_modules
npm-debug.log

Python

# Use the official Python image.
# https://hub.docker.com/_/python
FROM python:3.7

# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . .

# Install production dependencies.
RUN pip install Flask gunicorn

# Run the web service on container startup. Here we use the gunicorn
# webserver, with one worker process and 8 threads.
# For environments with multiple CPU cores, increase the number of workers
# to be equal to the cores available.
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app

Add a further .dockerignore file to ensure local files do not affect the container build process:

Dockerfile
README.md
*.pyc
*.pyo
*.pyd
__pycache__

Java

# Use the official maven/Java 8 image to create a build artifact.
# https://hub.docker.com/_/maven
FROM maven:3.5-jdk-8-alpine as builder

# Copy local code to the container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src

# Build a release artifact.
RUN mvn package -DskipTests

# Use AdoptOpenJDK for base image.
# It's important to use OpenJDK 8u191 or above that has container support enabled.
# https://hub.docker.com/r/adoptopenjdk/openjdk8
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim

# Copy the jar to the production image from the builder stage.
COPY --from=builder /app/target/helloworld-*.jar /helloworld.jar

# Run the web service on container startup.
CMD ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/helloworld.jar"]

C#

# Use Microsoft's official .NET image.
# https://hub.docker.com/r/microsoft/dotnet
FROM microsoft/dotnet:2.2-sdk

# Install production dependencies.
# Copy csproj and restore as distinct layers.
WORKDIR /app
COPY *.csproj .
RUN dotnet restore

# Copy local code to the container image.
COPY . .

# Build a release artifact.
RUN dotnet publish -c Release -o out

# Run the web service on container startup.
CMD ["dotnet", "out/helloworld-csharp.dll"]

Add a further .dockerignore file to ensure local files do not affect the container build process:

Dockerfile
README.md
**/obj/
**/bin/

PHP

# Use the official PHP 7.2 image.
# https://hub.docker.com/_/php
FROM php:7.2-apache

# Copy local code to the container image.
COPY index.php /var/www/html/

# Use the PORT environment variable in Apache configuration files.
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf

# Configure PHP for development.
# Switch to the production php.ini for production operations.
# RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# https://hub.docker.com/_/php#configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

Add a further .dockerignore file to ensure local files do not affect the container build process:

Dockerfile
README.md
vendor

Ruby

# Use the official Ruby image.
# https://hub.docker.com/_/ruby
FROM ruby:2.5

# Install production dependencies.
WORKDIR /usr/src/app
COPY Gemfile Gemfile.lock ./
ENV BUNDLE_FROZEN=true
RUN bundle install

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
CMD ["ruby", "./app.rb"]

Shell

FROM golang:1.11

WORKDIR /go/src/invoke

COPY invoke.go .
RUN go install -v

COPY . .

CMD ["invoke"]

Other

Cloud Run supports most languages. For sample Dockerfiles in languages other than the ones in this table, see the following:

However, in those samples, ignore and omit the material about service.yaml and Docker Hub, because Cloud Run does not use these.

Build your container image using Cloud Build, by running the following command from the directory containing the Dockerfile:

gcloud builds submit --tag gcr.io/PROJECT-ID/helloworld

where PROJECT-ID is your GCP project ID. You can get it by running gcloud config get-value project.

Upon success, you will see a SUCCESS message containing the image name (gcr.io/[PROJECT-ID]/helloworld). The image is stored in Container Registry and can be re-used if desired.

Deploying to Cloud Run

To deploy the container image:

  1. Deploy using the following command:

    gcloud beta run deploy --image gcr.io/PROJECT-ID/helloworld --platform managed

    Replace PROJECT-ID with your GCP project ID. You can view your project ID by running the command gcloud config get-value project.

    1. You will be prompted for the service name: press Enter to accept the default name, helloworld.
    2. You will be prompted for region: select the region of your choice, for example us-central1.
    3. You will be prompted to allow unauthenticated invocations: respond y .

    Then wait a few moments until the deployment is complete. On success, the command line displays the service URL.

  2. Visit your deployed container by opening the service URL in a web browser.

Cloud Run locations

Cloud Run is regional, which means the infrastructure that runs your Cloud Run services is located in a specific region and is managed by Google to be redundantly available across all the zones within that region.

Meeting your latency, availability, or durability requirements are primary factors for selecting the region where your Cloud Run services are run. You can generally select the region nearest to your users but you should consider the location of the other GCP products that are used by your Cloud Run service. Using GCP products together across multiple locations can affect your service's latency as well as cost.

Cloud Run is available in the following regions:

  • asia-northeast1 (Tokyo)
  • europe-west1 (Belgium)
  • us-central1 (Iowa)
  • us-east1 (South Carolina)

If you already created a Cloud Run service, you can view the region in the Cloud Run dashboard in the GCP Console.

Congratulations! You have just deployed an application packaged in a container image to Cloud Run. Cloud Run automatically and horizontally scales your container image to handle the received requests, then scales down when demand decreases. You only pay for the CPU, memory, and networking consumed during request handling.

Clean up

Removing your test project

While Cloud Run does not charge when the service is not in use, you might still be charged for storing the container image in Container Registry. You can delete your image or delete your GCP project to avoid incurring charges. Deleting your GCP project stops billing for all the resources used within that project.

  1. In the GCP Console, go to the Projects page.

    Go to the Projects page

  2. In the project list, select the project you want to delete and click Delete .
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

What's next

For more information on building a container from code source and pushing to Container Registry, see:

Was this page helpful? Let us know how we did:

Send feedback about...