Предоставляйте динамический контент и размещайте микросервисы с помощью Cloud Run

Используйте Cloud Run в паре с Firebase Hosting для генерации и предоставления динамического контента или для создания REST API в виде микросервисов.

С помощью Cloud Run вы можете развернуть приложение, упакованное в образ контейнера. Затем, используя Firebase Hosting , вы можете направлять HTTPS-запросы для запуска вашего контейнеризированного приложения.

Примеры использования и примеры работы Cloud Run в интеграции с Firebase Hosting можно найти в нашем обзоре бессерверных вычислений .


В этом руководстве показано, как:

  1. Напишите простое приложение "Hello World".
  2. Containerize an app and upload it to Artifact Registry
  3. Разверните образ контейнера в Cloud Run
  4. Прямая отправка запросов Hosting вашему контейнеризированному приложению.

Обратите внимание, что для повышения производительности отображения динамического контента вы можете дополнительно настроить параметры кэширования .

Прежде чем начать

Перед использованием Cloud Run необходимо выполнить ряд подготовительных задач, включая настройку учетной записи Cloud Billing , включение API Cloud Run и установку инструмента командной строки gcloud .

Настройте выставление счетов за ваш проект.

Cloud Run предлагает бесплатный лимит использования , но для его использования или тестирования вам все равно потребуется учетная запись Cloud Run Cloud Billing связанная с вашим проектом Firebase.

Включите API и установите SDK.

  1. Включите API Cloud Run в консоли Google API:

    1. Откройте страницу Cloud Run API в консоли Google API.

    2. При появлении запроса выберите свой проект Firebase.

    3. На странице Cloud Run API нажмите кнопку «Включить» .

  2. Установите и инициализируйте Cloud SDK.

  3. Убедитесь, что инструмент gcloud настроен для правильного проекта:

    gcloud config list

Шаг 1 : Напишите пример приложения.

Обратите внимание, что Cloud Run поддерживает множество других языков в дополнение к языкам, показанным в следующем примере.

Идти

  1. Создайте новую директорию с именем helloworld-go , затем перейдите в неё:

    mkdir helloworld-go
    cd helloworld-go
  2. Создайте новый файл с именем helloworld.go и добавьте в него следующий код:

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

    Этот код создает базовый веб-сервер, который прослушивает порт, определенный переменной среды PORT .

Ваше приложение завершено и готово к контейнеризации и загрузке в Artifact Registry .

Node.js

  1. Создайте новую директорию с именем helloworld-nodejs , затем перейдите в неё:

    mkdir helloworld-nodejs
    cd helloworld-nodejs
  2. Создайте файл package.json со следующим содержимым:

    {
      "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.22.1"
      }
    }
    
  3. Создайте новый файл с именем index.js и добавьте в него следующий код:

    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}!\n`);
    });
    
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log('Hello world listening on port', port);
    });
    

    Этот код создает базовый веб-сервер, который прослушивает порт, определенный переменной среды PORT .

Ваше приложение завершено и готово к контейнеризации и загрузке в Artifact Registry .

Python

  1. Создайте новую директорию с именем helloworld-python , затем перейдите в неё:

    mkdir helloworld-python
    cd helloworld-python
  2. Создайте новый файл с именем app.py и добавьте в него следующий код:

    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)))
    

    Этот код создает базовый веб-сервер, который прослушивает порт, определенный переменной среды PORT .

Ваше приложение завершено и готово к контейнеризации и загрузке в Artifact Registry .

Java

  1. Установите Java SE 8 или более позднюю версию JDK и CURL .

    Обратите внимание, что это необходимо сделать только для создания нового веб-проекта на следующем шаге. Dockerfile, который будет описан позже, загрузит все зависимости в контейнер.

  2. В консоли создайте новый пустой веб-проект, используя cURL, а затем выполните команды распаковки:

    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d name=helloworld \
        -d artifactId=helloworld \
        -o helloworld.zip
    unzip helloworld.zip

    Это создаст проект SpringBoot.

  3. Update the SpringBootApplication 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);
      }
    }
    

    Этот код создает базовый веб-сервер, который прослушивает порт, определенный переменной среды PORT .

Ваше приложение завершено и готово к контейнеризации и загрузке в Artifact Registry .

Шаг 2 : Контейнеризуйте приложение и загрузите его в Artifact Registry

  1. Для контейнеризации тестового приложения создайте новый файл с именем Dockerfile в той же директории, что и исходные файлы. Скопируйте следующее содержимое в этот файл.

    Идти

    # Use the official Golang image to create a build artifact.
    # This is based on Debian and sets the GOPATH to /go.
    FROM golang:latest AS builder
    
    ARG TARGETOS
    ARG TARGETARCH
    
    # Create and change to the app directory.
    WORKDIR /app
    
    # Copy local code to the container image.
    COPY . ./
    
    # Install dependencies and tidy up the go.mod and go.sum files.
    RUN go mod tidy
    
    # Build the binary.
    # -mod=readonly ensures immutable go.mod and go.sum in container builds.
    RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -mod=readonly -v -o server
    
    # Use the official Alpine image for a lean production container.
    # https://hub.docker.com/_/alpine
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM alpine:3
    RUN apk add --no-cache ca-certificates
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /app/server /server
    
    # Run the web service on container startup.
    CMD ["/server"]
    

    Node.js

    # Use the official lightweight Node.js 12 image.
    # https://hub.docker.com/_/node
    FROM node:12-slim
    
    # 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" ]
    

    Python

    # Use the official lightweight Python image.
    # https://hub.docker.com/_/python
    FROM python:3.7-slim
    
    # Allow statements and log messages to immediately appear in the Knative logs
    ENV PYTHONUNBUFFERED True
    
    # 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 --timeout 0 app:app
    

    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 the Official OpenJDK image for a lean production stage of our multi-stage build.
    # https://hub.docker.com/_/openjdk
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM openjdk:8-jre-alpine
    
    # 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", "-jar", "/helloworld.jar"]
    

  2. Создайте образ контейнера с помощью Cloud Build , выполнив следующую команду из каталога, содержащего ваш Dockerfile:

    gcloud builds submit --tag gcr.io/PROJECT_ID/helloworld

    В случае успеха вы увидите сообщение SUCCESS, содержащее название изображения.
    ( gcr.io/ PROJECT_ID /helloworld ).

Образ контейнера теперь хранится в Artifact Registry и при желании может быть использован повторно.

Обратите внимание, что вместо Cloud Build вы можете использовать локально установленную версию Docker для сборки контейнера локально .

Шаг 3 : Разверните образ контейнера в Cloud Run

  1. Развертывание выполняется с помощью следующей команды:

    gcloud run deploy --image gcr.io/PROJECT_ID/helloworld

  2. При появлении запроса:

  3. Подождите несколько минут, пока завершится развертывание. В случае успеха в командной строке отобразится URL-адрес сервиса. Например https://helloworld- RANDOM_HASH -us-central1.a.run.app

  4. Чтобы получить доступ к развернутому контейнеру, откройте URL-адрес сервиса в веб-браузере.

На следующем шаге вы узнаете, как получить доступ к этому контейнеризированному приложению по URL-адресу Firebase Hosting , чтобы оно могло генерировать динамический контент для вашего сайта, размещенного на Firebase.

Шаг 4: Направляйте запросы на размещение вашего контейнеризированного приложения.

С помощью правил перезаписи вы можете направлять запросы, соответствующие определенным шаблонам, в одно место назначения.

В следующем примере показано, как направлять все запросы со страницы /helloworld на вашем Hosting на запуск и выполнение экземпляра контейнера helloworld .

  1. Убедитесь, что:

    Подробные инструкции по установке CLI и инициализации Hosting см. в руководстве по началу работы с Hosting .

  2. Откройте файл firebase.json .

  3. Добавьте следующую конфигурацию rewrite в раздел hosting :

    "hosting": {
      // ...
    
      // Add the "rewrites" attribute within "hosting"
      "rewrites": [ {
        "source": "/helloworld",
        "run": {
          "serviceId": "helloworld",  // "service name" (from when you deployed the container image)
          "region": "us-central1",    // optional (if omitted, default is us-central1)
          "pinTag": true              // optional (see note below)
        }
      } ]
    }
  4. Разверните конфигурацию хостинга на своем сайте, выполнив следующую команду из корневого каталога вашего проекта:

    firebase deploy --only hosting

Your container is now reachable via the following URLs:

Visit the Hosting configuration page for more details about rewrite rules . You can also learn about the priority order of responses for various Hosting configurations.

Протестируйте локально.

During development, you can run and test your container image locally. For detailed instructions, visit the Cloud Run documentation .

Следующие шаги