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

Połącz Cloud Run z Firebase Hosting, aby generować i udostępniać zawartość dynamiczną lub tworzyć interfejsy API typu 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 uruchamiać aplikację w kontenerze.

  • Cloud Run obsługuje kilka języków (w tym Go, Node.js, Python i Java), co zapewnia elastyczność korzystania z wybranego języka programowania i platformy.
  • Cloud Run automatycznie skaluje obraz kontenera w poziomie, 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 zastosowań i przykłady kodu dla Cloud Run zintegrowanego z Firebase Hosting znajdziesz w naszym omówieniu rozwiązań bezserwerowych.


Z tego przewodnika dowiesz się, jak:

  1. Tworzenie prostej aplikacji Hello World
  2. Skonteneryzowanie aplikacji i przesłanie jej do Artifact Registry
  3. Wdrażanie obrazu kontenera w Cloud Run
  4. Kierowanie żądań Hosting do aplikacji w kontenerze

Pamiętaj, że aby zwiększyć wydajność udostępniania zawartości dynamicznej, możesz opcjonalnie dostosować ustawienia pamięci podręcznej.

Zanim zaczniesz

Zanim zaczniesz korzystać z Cloud Run, musisz wykonać kilka czynności wstępnych, takich jak skonfigurowanie konta Cloud Billing, włączenie interfejsu API Cloud Run i zainstalowanie narzędzia wiersza poleceń gcloud.

Skonfiguruj płatności w projekcie.

Cloud Run oferuje bezpłatny limit wykorzystania, ale aby korzystać z Cloud Run lub wypróbować tę usługę, musisz mieć konto Cloud Billing powiązane z projektem w 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 stronę interfejsu API Cloud Run w konsoli interfejsów API Google.

    2. Gdy pojawi się prośba, wybierz projekt w 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. Utwórz 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 i przejdź do niego:

    mkdir helloworld-go
    cd helloworld-go
    1. 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 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.22.1"
      }
    }
    
  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 JDK oraz CURL.

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

  2. W konsoli utwórz nowy pusty projekt internetowy za pomocą poleceń cURL, a następnie 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ę SpringBootApplication w pliku src/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. Skonteneryzuj aplikację 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 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 podane poniżej polecenie z katalogu zawierającego plik Dockerfile:

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

    Gdy operacja się powiedzie, 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.

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

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ę prośba:

  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. Zobacz wdrożony kontener, otwierając URL usługi w przeglądarce.

W następnym kroku dowiesz się, jak uzyskać dostęp do tej skonteneryzowanej aplikacji z adresu URL Firebase Hosting, aby mogła generować zawartość dynamiczną dla witryny hostowanej w Firebase.

Krok 4. Kieruj żądania hostingu do skonteneryzowanej aplikacji

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 przekierować wszystkie żądania ze strony /helloworld w witrynie Hosting, aby uruchomić instancję kontenera helloworld.

  1. Sprawdź, czy:

    Szczegółowe instrukcje instalowania interfejsu wiersza poleceń i inicjowania Hosting znajdziesz w przewodniku dla początkujących użytkowników 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

Kontener jest teraz dostępny pod tymi adresami URL:

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

  • wszystkie połączone własne domeny:
    CUSTOM_DOMAIN/

Więcej informacji o regułach przepisywania znajdziesz na stronie konfiguracji Hosting (w języku angielskim). 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 dokumentacji Cloud Run.

Dalsze kroki