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

Объедините Cloud Run с Firebase Hosting чтобы создавать и обслуживать динамический контент или создавать REST API в виде микросервисов.

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

  • Cloud Run поддерживает несколько языков (включая Go, Node.js, Python и Java), что дает вам возможность использовать язык программирования и платформу по вашему выбору.
  • Cloud Run автоматически и горизонтально масштабирует образ контейнера для обработки полученных запросов, а затем уменьшает масштаб, когда спрос снижается.
  • Вы платите только за процессор, память и сеть, использованные во время обработки запроса.

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


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

  1. Напишите простое приложение Hello World.
  2. Контейнеризируйте приложение и загрузите его в 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. Включите Cloud Run API в консоли 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 .

  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.21.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 .

  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 .

  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. Обновите класс SpringBootApplication в src/main/java/com/example/helloworld/HelloworldApplication.java , добавив @RestController для обработки сопоставления / , а также добавьте поле @Value для предоставления переменной среды TARGET :

    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"]
    

    # 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" ]
    

    # 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
    

    # 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

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

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

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

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

Для достижения наилучшей производительности разместите службу Cloud Run вместе с Hosting , используя следующие регионы:

  • us-west1
  • us-central1
  • us-east1
  • europe-west1
  • asia-east1

Перезапись в Cloud Run с Hosting поддерживается в следующих регионах:

  • asia-east1
  • asia-east2
  • asia-northeast1
  • asia-northeast2
  • asia-northeast3
  • asia-south1
  • asia-south2
  • asia-southeast1
  • asia-southeast2
  • australia-southeast1
  • australia-southeast2
  • europe-central2
  • europe-north1
  • europe-southwest1
  • europe-west1
  • europe-west12
  • europe-west2
  • europe-west3
  • europe-west4
  • europe-west6
  • europe-west8
  • europe-west9
  • me-central1
  • me-west1
  • northamerica-northeast1
  • northamerica-northeast2
  • southamerica-east1
  • southamerica-west1
  • us-central1
  • us-east1
  • us-east4
  • us-east5
  • us-south1
  • us-west1
  • us-west2
  • us-west3
  • us-west4
  • us-west1
  • us-central1
  • us-east1
  • europe-west1
  • asia-east1

  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

Благодаря этой функции вы можете гарантировать, что версия вашей службы Cloud Run для создания динамического контента вашего сайта синхронизируется с вашими статическими ресурсами Hosting и конфигурацией Hosting . Кроме того, эта функция позволяет вам просматривать ваши перезаписи в Cloud Run на каналах предварительного просмотра Hosting .

Если вы добавите "pinTag": true в блок run конфигурации hosting.rewrites , ваши статические ресурсы и конфигурация Hosting будут закреплены за самой последней версией службы Cloud Run на момент развертывания. Если вы откатываете версию своего сайта, редакция «закрепленного» сервиса Cloud Run также откатывается.

Эта функция использует теги Cloud Run , которые имеют ограничение в 1000 тегов на сервис и 2000 тегов на регион. Это означает, что после сотен развертываний самые старые версии сайта могут перестать работать.

Теперь ваш контейнер доступен по следующим URL-адресам:

Посетите страницу конфигурации Hosting для получения более подробной информации о правилах перезаписи . Также вы можете узнать о приоритете ответов для различных конфигураций Hosting .

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

Во время разработки вы можете запускать и тестировать образ контейнера локально. Подробные инструкции можно найти в документации Cloud Run .

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