Obsługa treści dynamicznych i hostowanie mikroserwisów za pomocą Cloud Run

Połącz usługę Cloud Run z usługą Firebase Hosting, aby generować i wyświetlać treści dynamiczne lub tworzyć interfejsy API REST jako mikroserwisy.

Za pomocą Cloud Run możesz wdrożyć aplikację spakowaną do obrazu kontenera. Następnie za pomocą Firebase Hosting możesz kierować żądania HTTPS, aby wywołać aplikację w kontenerze.

  • Cloud Run obsługuje kilka języków (w tym Go, Node.js, Python i Java), co daje Ci możliwość używania wybranego języka programowania i ramy.
  • Cloud Run automatycznie skaluje w poziomie obraz kontenera, aby obsługiwać otrzymane żądania, a następnie skaluje go w dół, gdy zapotrzebowanie maleje.
  • Płacisz tylko za procesor, pamięć i sieć wykorzystywane w trakcie obsługiwania żądań.

Przykładowe przypadki użycia i próbki dotyczące usługi Cloud Run zintegrowanej z Firebase Hosting znajdziesz w artykule Informacje o usłudze bez serwera.


Z tego przewodnika dowiesz się, jak:

  1. Tworzenie prostej aplikacji Hello World
  2. Konteneryzowanie aplikacji i przesyłanie jej do Artifact Registry
  3. Wdróż obraz kontenera w Cloud Run
  4. Kierowanie Hosting do aplikacji konteneryzowanej

Aby zwiększyć skuteczność dostarczania treści dynamicznych, możesz opcjonalnie dostosować ustawienia pamięci podręcznej.

Zanim zaczniesz

Zanim zaczniesz używać Cloud Run, musisz wykonać kilka wstępnych czynności, w tym skonfigurować konto Cloud Billing, włączyć interfejs API Cloud Run i zainstalować narzędzie wiersza poleceń gcloud.

Konfigurowanie płatności w projekcie

Cloud Run oferuje bezpłatną pulę wykorzystania, ale aby korzystać z Cloud Run lub go wypróbować, musisz mieć konto Cloud Billing powiązane ze swoim projektem Firebase.

Włącz interfejs API i zainstaluj pakiet SDK

  1. Włącz interfejs API Cloud Run w konsoli interfejsów API Google:

    1. Otwórz stronę Cloud Run interfejsu API w konsoli interfejsów API Google.

    2. Gdy pojawi się taka prośba, wybierz projekt Firebase.

    3. Na stronie interfejsu API Cloud Run kliknij Włącz.

  2. Zainstaluj i zainicjuj pakiet Cloud SDK.

  3. Sprawdź, czy narzędzie gcloud jest skonfigurowane pod kątem odpowiedniego projektu:

    gcloud config list

Krok 1. Utwórz przykładową aplikację

Pamiętaj, że Cloud Run obsługuje wiele innych języków oprócz tych wymienionych w tym przykładzie.

Go

  1. Utwórz nowy katalog o nazwie helloworld-go, a następnie przejdź do tego katalogu:

    mkdir helloworld-go
    cd helloworld-go
  2. Utwórz nowy plik o nazwie helloworld.go i dodaj do niego ten kod:

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

    Ten kod tworzy podstawowy serwer WWW, który nasłuchuje na porcie określonym przez zmienną środowiskową PORT.

Aplikacja jest gotowa i możesz ją teraz skonteneryzować i przesłać do Artifact Registry.

Node.js

  1. Utwórz nowy katalog o nazwie helloworld-nodejs i przejdź do niego:

    mkdir helloworld-nodejs
    cd helloworld-nodejs
  2. Utwórz plik package.json z tą zawartością:

    {
      "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. Utwórz nowy plik o nazwie index.js i dodaj do niego ten kod:

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

    Ten kod tworzy podstawowy serwer WWW, który nasłuchuje na porcie określonym przez zmienną środowiskową PORT.

Aplikacja jest gotowa i możesz ją teraz skonteneryzować i przesłać do Artifact Registry.

Python

  1. Utwórz nowy katalog o nazwie helloworld-python i przejdź do niego:

    mkdir helloworld-python
    cd helloworld-python
  2. Utwórz nowy plik o nazwie app.py i dodaj do niego ten kod:

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

    Ten kod tworzy podstawowy serwer WWW, który nasłuchuje na porcie określonym przez zmienną środowiskową PORT.

Aplikacja jest gotowa i możesz ją teraz skonteneryzować i przesłać do Artifact Registry.

Java

  1. Zainstaluj Java SE 8 lub nowszą wersję JDK oraz CURL.

    Pamiętaj, że musimy to zrobić tylko po to, aby utworzyć nowy projekt internetowy w następnym kroku. Plik Dockerfile, którego opis znajdziesz poniżej, wczyta wszystkie zależności do kontenera.

  2. W konsoli utwórz nowy pusty projekt internetowy za pomocą poleceń cURL i unzip:

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

    Spowoduje to utworzenie projektu SpringBoot.

  3. Zaktualizuj klasę SpringBootApplicationsrc/main/java/com/example/helloworld/HelloworldApplication.java, dodając element @RestController do obsługi mapowania /, a także pole @Value do podawania zmiennej środowiskowej 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);
      }
    }
    

    Ten kod tworzy podstawowy serwer WWW, który nasłuchuje na porcie określonym przez zmienną środowiskową PORT.

Aplikacja jest gotowa i możesz ją teraz skonteneryzować i przesłać do Artifact Registry.

Krok 2. Umieść aplikację w kontenerze i prześlij ją do Artifact Registry

  1. Skonteneryzuj przykładową aplikację, tworząc nowy plik o nazwie Dockerfile w tym samym katalogu, w którym znajdują się pliki źródłowe. Skopiuj do pliku te treści.

    Go

    # 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. Utwórz obraz kontenera za pomocą Cloud Build, uruchamiając podane poniżej polecenie z katalogu zawierającego plik Dockerfile:

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

    Po pomyślnym przesłaniu wyświetli się komunikat o powodzeniu z nazwą obrazu
    (gcr.io/PROJECT_ID/helloworld).

Obraz kontenera jest teraz przechowywany w Artifact Registry i w razie potrzeby można go użyć ponownie.

Pamiętaj, że zamiast Cloud Build możesz użyć zainstalowanej lokalnie wersji Dockera, aby utworzyć kontener lokalnie.

Krok 3. Wdróż obraz kontenera do Cloud Run

  1. Wdróż usługę za pomocą tego polecenia:

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

  2. Gdy pojawi się odpowiedni komunikat:

  3. Zaczekaj chwilę na zakończenie wdrażania. Jeśli polecenie zadziała, w wierszu poleceń wyświetli się URL usługi. Przykład:https://helloworld-RANDOM_HASH-us-central1.a.run.app

  4. Możesz teraz zobaczyć wdrożony kontener, otwierając URL usługi w przeglądarce.

W następnym kroku dowiesz się, jak uzyskać dostęp do tej aplikacji w kontenerze przez adres URLFirebase Hosting, aby mogła generować dynamiczne treści dla witryny hostowanej w Firebase.

Krok 4. Przekierowuj żądania hostingu do aplikacji w kontenerze

Za pomocą reguł przekształcania możesz kierować żądania pasujące do określonych wzorców do jednego miejsca docelowego.

Z tego przykładu dowiesz się, jak kierować wszystkie żądania ze strony /helloworld w witrynie Hosting, aby uruchomić i uruchomić instancję kontenera helloworld.

  1. Sprawdź, czy:

    Szczegółowe instrukcje dotyczące instalowania interfejsu wiersza poleceń i inicjowania usługi Hosting znajdziesz w przewodniku Pierwsze kroki z Hosting.

  2. Otwórz plik firebase.json.

  3. W sekcji hosting dodaj tę konfigurację rewrite:

    "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. Wdrożyć konfigurację hostingu na swojej stronie, uruchamiając to polecenie w katalogu głównym katalogu projektu:

    firebase deploy --only hosting

Twój kontener jest teraz dostępny pod tymi adresami URL:

  • Twoje subdomeny Firebase:
    PROJECT_ID.web.app/PROJECT_ID.firebaseapp.com/

  • dowolne połączone domeny niestandardowe:
    CUSTOM_DOMAIN/

Więcej informacji o regułach przekierowania znajdziesz na stronie konfiguracji Hosting. Możesz też dowiedzieć się więcej o kolejności priorytetów odpowiedzi w różnych konfiguracjach Hosting.

Testowanie lokalnie

Podczas tworzenia możesz uruchomić i przetestować obraz kontenera lokalnie. Szczegółowe instrukcje znajdziesz w dokumentacji Cloud Run.

Dalsze kroki