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

Połącz Cloud Run z Hostingiem Firebase, aby generować i wyświetlać zawartość dynamiczną, lub tworzyć interfejsy API REST jako mikroserwisy.

Za pomocą Cloud Run możesz wdrożyć aplikację spakowaną do obrazu kontenera. Następnie za pomocą Hostingu Firebase możesz kierować żądania HTTPS, które aktywują aplikację znajdującą się w kontenerze.

  • Cloud Run obsługuje kilka języków (m.in. Go, Node.js, Pythona i Java), dzięki czemu możesz korzystać z wybranego języka programowania i platformy.
  • Cloud Run automatycznie i w poziomie skaluje obraz kontenera w celu obsługi otrzymanych żądań, a następnie skaluje w dół, gdy zapotrzebowanie maleje.
  • Płacisz tylko za procesor, pamięć i sieć wykorzystywane w trakcie obsługiwania żądań.

Przykładowe zastosowania i przykłady użycia Cloud Run zintegrowanego z Hostingiem Firebase znajdziesz w naszym omówieniu bezserwerowym.


Z tego przewodnika dowiesz się, jak:

  1. Napisanie prostej aplikacji Hello World
  2. Tworzenie kontenera aplikacji i przesyłanie jej do Container Registry
  3. Wdrażanie obrazu kontenera w Cloud Run
  4. Kierowanie żądań Hostingu do aplikacji skonteneryzowanej

Aby poprawić wydajność 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 czynności początkowych, w tym skonfigurować konto rozliczeniowe Cloud, włączyć Cloud Run API i zainstalować narzędzie wiersza poleceń gcloud.

Skonfiguruj płatności w projekcie

Cloud Run oferuje bezpłatny limit wykorzystania, jednak aby go wypróbować lub wypróbować, musisz mieć konto rozliczeniowe Cloud powiązane z projektem Firebase.

Włączanie interfejsu API i instalowanie pakietu SDK

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

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

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

    3. Na stronie Cloud Run API 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 oprócz języków pokazanych w przykładzie poniżej Cloud Run obsługuje wiele innych języków.

Go

  1. Utwórz nowy katalog o nazwie helloworld-go, a następnie przenieś na niego katalog:

    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ą skonteneryzować i przesłać do Container Registry.

Node.js

  1. Utwórz nowy katalog o nazwie helloworld-nodejs, a następnie przenieś do niego katalog:

    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.19.2"
      }
    }
    
  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ą skonteneryzować i przesłać do Container Registry.

Python

  1. Utwórz nowy katalog o nazwie helloworld-python, a następnie przenieś do niego katalog:

    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ą skonteneryzować i przesłać do Container Registry.

Java

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

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

  2. W konsoli utwórz nowy pusty projekt internetowy za pomocą narzędzia cURL, a następnie rozpakuj polecenia:

    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 src/main/java/com/example/helloworld/HelloworldApplication.java, dodając @RestController do obsługi mapowania / oraz pole @Value, aby udostępnić 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ą skonteneryzować i przesłać do Container Registry.

Krok 2. Skonteneryzuj aplikację i prześlij ją do Container Registry

  1. Skonteneryzujesz przykładową aplikację, tworząc nowy plik o nazwie Dockerfile w tym samym katalogu co pliki źródłowe. Skopiuj poniższą zawartość do swojego pliku.

    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
    
    # Retrieve application dependencies using go modules.
    # Allows container builds to reuse downloaded dependencies.
    COPY go.* ./
    RUN go mod download
    
    # Copy local code to the container image.
    COPY . ./
    
    # 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 Twój plik Dockerfile:

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

    Jeśli operacja się uda, wyświetli się komunikat z informacją o udanym przeprowadzeniu operacji i nazwą obrazu
    (gcr.io/PROJECT_ID/helloworld).

Obraz kontenera jest teraz przechowywany w Container 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óż przy użyciu tego polecenia:

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

  2. Gdy pojawi się odpowiedni komunikat:

Aby uzyskać najlepszą wydajność, skolokuj swoją usługę Cloud Run z Hostingiem przy użyciu tych regionów:

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

Przepisywanie w Cloud Run z Hostingu jest obsługiwane w tych regionach:

  • 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. Zaczekaj chwilę na zakończenie wdrożenia. Kiedy operacja się uda, w wierszu poleceń wyświetli się URL usługi. Przykład: https://helloworld-RANDOM_HASH-us-central1.a.run.app

  2. Przejdź do wdrożonego kontenera, otwierając adres URL usługi w przeglądarce.

W następnym kroku pokażemy, jak uzyskać dostęp do skonteneryzowanej aplikacji z adresu URL Hostingu Firebase, aby móc generować treści dynamiczne na potrzeby witryny hostowanej w Firebase.

Krok 4. Przekaż żądania hostingu do aplikacji skonteneryzowanej

Dzięki regułom przepisywania możesz kierować żądania pasujące do określonych wzorców do jednego miejsca docelowego.

Z przykładu poniżej dowiesz się, jak kierować wszystkie żądania ze strony /helloworld w witrynie Hostingu, aby aktywować uruchamianie i uruchamianie instancji kontenera helloworld.

  1. Sprawdź, czy:

    Szczegółowe instrukcje instalowania interfejsu wiersza poleceń i inicjowania hostowania znajdziesz w Przewodniku wprowadzającym do hostingu.

  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óż w swojej witrynie konfigurację hostingu, uruchamiając to polecenie z katalogu głównego projektu:

    firebase deploy --only hosting

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

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

  • Wszelkie połączone domeny niestandardowe:
    CUSTOM_DOMAIN/

Szczegółowe informacje o regułach przepisywania znajdziesz na stronie konfiguracji hostingu. Możesz też zapoznać się z priorytetem odpowiedzi dla różnych konfiguracji Hostingu.

Przetestuj lokalnie

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

Dalsze kroki