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

Połącz Cloud Run z Firebase Hosting, aby generować i obsługiwać 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ływać aplikację w kontenerze.

  • Cloud Run obsługuje kilka języków (w tym Go, Node.js, Python i Java), dzięki czemu możesz używać wybranego języka programowania i frameworka.
  • 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łady zastosowania i próbki Cloud Run zintegrowanego z Firebase Hosting znajdziesz w omówieniu technologii bezserwerowej.


Z tego przewodnika dowiesz się, jak:

  1. Napisz prostą aplikację Hello World
  2. Konteneryzowanie aplikacji i przesyłanie jej do Artifact Registry
  3. Wdrażanie obrazu kontenera w Cloud Run
  4. Kierowanie żądań Hosting bezpośrednio do aplikacji konteneryzowanej

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

Zanim zaczniesz

Zanim zaczniesz korzystać z Cloud Run, musisz wykonać kilka wstępnych zadań, w tym skonfigurować konto Cloud Billing, włączyć interfejs Cloud Run API i zainstalować narzędzie wiersza poleceń gcloud.

Konfigurowanie płatności w projekcie

Cloud Run oferuje bezpłatny limit wykorzystania, ale aby korzystać z Cloud Run lub ją wypróbować, musisz mieć Cloud Billingkonto powiązane z projektem Firebase.

Włączanie interfejsu API i instalowanie pakietu SDK

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

    1. Otwórz Cloud Runstronę 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 SDK Cloud.

  3. Sprawdź, czy narzędzie gcloud jest skonfigurowane dla właściwego projektu:

    gcloud config list

Krok 1. Napisz przykładową aplikację

Pamiętaj, że Cloud Run obsługuje wiele innych języków oprócz tych, które są widoczne w poniższym przykładzie.

Go

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

    mkdir helloworld-go
    cd helloworld-go
  2. Utwórz nowy plik o nazwie helloworld.go, a następnie dodaj 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, a następnie przejdź do niego:

    mkdir helloworld-nodejs
    cd helloworld-nodejs
  2. Utwórz plik package.json o tej 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.2"
      }
    }
    
  3. Utwórz nowy plik o nazwie index.js, a następnie dodaj 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, a następnie przejdź do niego:

    mkdir helloworld-python
    cd helloworld-python
  2. Utwórz nowy plik o nazwie app.py, a następnie dodaj 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 nowszy JDKCURL.

    Pamiętaj, że musisz to zrobić tylko po to, aby w następnym kroku utworzyć nowy projekt internetowy. Plik Dockerfile, który zostanie opisany później, załaduje wszystkie zależności do kontenera.

  2. W konsoli utwórz nowy pusty projekt internetowy za pomocą poleceń cURL, a następnie poleceń rozpakowywania:

    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 @RestController do obsługi mapowania /, a także dodaj pole @Value, aby podać zmienną środowiskową 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. Utwórz kontener aplikacji i prześlij go 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 tę treść.

    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 to polecenie z katalogu zawierającego Dockerfile:

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

    Po zakończeniu operacji wyświetli się komunikat z informacją o udanym przeprowadzeniu operacji i 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.

Zamiast Cloud Build możesz użyć lokalnie zainstalowanej wersji Dockera, aby lokalnie utworzyć kontener.

Krok 3. Wdróż obraz kontenera w Cloud Run

  1. Wdróż za pomocą tego polecenia:

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

  2. Gdy pojawi się odpowiedni komunikat:

  3. Poczekaj chwilę na zakończenie wdrażania. Kiedy operacja zostanie wykonana, w wierszu poleceń wyświetli się URL usługi. Na przykład:https://helloworld-RANDOM_HASH-us-central1.a.run.app

  4. Otwórz adres URL usługi w przeglądarce, aby zobaczyć wdrożony kontener.

W następnym kroku dowiesz się, jak uzyskać dostęp do tej aplikacji w kontenerze z użyciem adresu URL, aby mogła generować dynamiczne treści dla Twojej witryny hostowanej w Firebase.Firebase Hosting

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

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

Poniższy przykład pokazuje, jak skierować wszystkie żądania ze strony /helloworld w witrynie Hosting, aby uruchamiały i uruchamiały instancję kontenera helloworld.

  1. Sprawdź, czy:

    Szczegółowe instrukcje instalacji interfejsu wiersza poleceń i inicjowaniaHosting znajdziesz w przewodniku Pierwsze kroki z Hosting.

  2. Otwórz plik firebase.json.

  3. Dodaj tę konfigurację rewrite w sekcji 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. Wdróż konfigurację hostingu w witrynie, uruchamiając to polecenie w katalogu głównym projektu:

    firebase deploy --only hosting

Do kontenera można teraz uzyskać dostęp za pomocą tych adresów URL:

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

  • Wszystkie połączone domeny niestandardowe:
    CUSTOM_DOMAIN/

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

Testowanie lokalne

Podczas tworzenia możesz uruchamiać i testować obraz kontenera lokalnie. Szczegółowe instrukcje znajdziesz w Cloud Rundokumentacji.

Dalsze kroki