Phân phát nội dung động và dịch vụ vi mô lưu trữ bằng Cloud Run

Ghép nối Cloud Run với Firebase Hosting để tạo và phân phát nội dung động hoặc xây dựng API REST dưới dạng các dịch vụ vi mô.

Khi sử dụng Cloud Run, bạn có thể triển khai một ứng dụng được đóng gói trong một hình ảnh vùng chứa. Sau đó, bằng cách sử dụng Firebase Hosting, bạn có thể chuyển các yêu cầu HTTPS để kích hoạt ứng dụng được chứa trong vùng chứa.

  • Cloud Run hỗ trợ nhiều ngôn ngữ (bao gồm Go, Node.js, Python và Java), giúp bạn linh hoạt sử dụng ngôn ngữ lập trình và khung mà bạn chọn.
  • Cloud Run tự động và mở rộng theo chiều ngang hình ảnh vùng chứa để xử lý các yêu cầu nhận được, sau đó giảm quy mô khi nhu cầu giảm.
  • Bạn chỉ trả tiền cho CPU, bộ nhớ và mạng được sử dụng trong quá trình xử lý yêu cầu.

Để xem các trường hợp sử dụng và mẫu ví dụ cho Cloud Run được tích hợp với Firebase Hosting, hãy truy cập vào bài tổng quan về mô hình không máy chủ của chúng tôi.


Hướng dẫn này sẽ cho bạn biết cách:

  1. Viết một ứng dụng Hello World đơn giản
  2. Đóng gói ứng dụng vào vùng chứa và tải ứng dụng đó lên Artifact Registry
  3. Triển khai hình ảnh vùng chứa đến Cloud Run
  4. Chuyển các yêu cầu Hosting đến ứng dụng nằm trong vùng chứa của bạn

Xin lưu ý rằng để cải thiện hiệu suất phân phát nội dung động, bạn có thể điều chỉnh chế độ cài đặt bộ nhớ đệm (không bắt buộc).

Trước khi bắt đầu

Trước khi sử dụng Cloud Run, bạn cần hoàn tất một số việc ban đầu, bao gồm cả việc thiết lập tài khoản Cloud Billing, bật API Cloud Run và cài đặt công cụ dòng lệnh gcloud.

Thiết lập thông tin thanh toán cho dự án của bạn

Cloud Run cung cấp hạn mức sử dụng miễn phí, nhưng bạn vẫn phải có tài khoản Cloud Billing được liên kết với dự án Firebase để sử dụng hoặc dùng thử Cloud Run.

Bật API và cài đặt SDK

  1. Bật API Cloud Run trong Bảng điều khiển API Google:

    1. Mở trang Cloud Run API trong Google API Console.

    2. Khi được nhắc, hãy chọn dự án Firebase của bạn.

    3. Nhấp vào Bật trên trang API Cloud Run.

  2. Cài đặt và khởi chạy Cloud SDK.

  3. Kiểm tra để đảm bảo công cụ gcloud được định cấu hình cho đúng dự án:

    gcloud config list

Bước 1: Viết ứng dụng mẫu

Xin lưu ý rằng Cloud Run hỗ trợ nhiều ngôn ngữ khác ngoài những ngôn ngữ xuất hiện trong mẫu sau.

Tìm

  1. Tạo một thư mục mới có tên là helloworld-go, sau đó thay đổi thư mục thành thư mục này:

    mkdir helloworld-go
    cd helloworld-go
  2. Tạo một tệp mới có tên là helloworld.go, sau đó thêm mã sau:

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

    Đoạn mã này tạo một máy chủ web cơ bản, lắng nghe trên cổng do biến môi trường PORT xác định.

Ứng dụng của bạn đã hoàn tất và sẵn sàng được đóng gói vào vùng chứa và tải lên Artifact Registry.

Node.js

  1. Tạo một thư mục mới có tên helloworld-nodejs, sau đó thay đổi thư mục thành thư mục đó:

    mkdir helloworld-nodejs
    cd helloworld-nodejs
  2. Tạo tệp package.json có các nội dung sau:

    {
      "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. Tạo một tệp mới có tên là index.js, sau đó thêm mã sau:

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

    Đoạn mã này tạo một máy chủ web cơ bản, lắng nghe trên cổng do biến môi trường PORT xác định.

Ứng dụng của bạn đã hoàn tất và sẵn sàng được đóng gói vào vùng chứa và tải lên Artifact Registry.

Python

  1. Tạo một thư mục mới có tên helloworld-python, sau đó thay đổi thư mục thành thư mục đó:

    mkdir helloworld-python
    cd helloworld-python
  2. Tạo một tệp mới có tên là app.py, sau đó thêm mã sau:

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

    Đoạn mã này tạo một máy chủ web cơ bản, lắng nghe trên cổng do biến môi trường PORT xác định.

Ứng dụng của bạn đã hoàn tất và sẵn sàng được đóng gói vào vùng chứa và tải lên Artifact Registry.

Java

  1. Cài đặt JDK Java SE 8 trở lênCURL.

    Xin lưu ý rằng chúng ta chỉ cần làm việc này để tạo dự án web mới ở bước tiếp theo. Dockerfile (được mô tả sau) sẽ tải tất cả các phần phụ thuộc vào vùng chứa.

  2. Trên bảng điều khiển, hãy tạo một dự án web trống mới bằng cách sử dụng cURL rồi giải nén các lệnh:

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

    Thao tác này sẽ tạo một dự án SpringBoot.

  3. Cập nhật lớp SpringBootApplication trong src/main/java/com/example/helloworld/HelloworldApplication.java bằng cách thêm một @RestController để xử lý mối liên kết /, đồng thời thêm một trường @Value để cung cấp biến môi trường 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);
      }
    }
    

    Đoạn mã này tạo một máy chủ web cơ bản, lắng nghe trên cổng do biến môi trường PORT xác định.

Ứng dụng của bạn đã hoàn tất và sẵn sàng được đóng gói vào vùng chứa và tải lên Artifact Registry.

Bước 2: Đóng gói ứng dụng vào vùng chứa và tải ứng dụng đó lên Artifact Registry

  1. Tạo vùng chứa cho ứng dụng mẫu bằng cách tạo một tệp mới có tên Dockerfile trong cùng thư mục với các tệp nguồn. Sao chép nội dung sau vào tệp của bạn.

    Tìm

    # 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. Tạo hình ảnh vùng chứa bằng cách sử dụng Cloud Build bằng cách chạy lệnh sau từ thư mục chứa Dockerfile:

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

    Khi thành công, bạn sẽ thấy thông báo THÀNH CÔNG có chứa tên hình ảnh
    (gcr.io/PROJECT_ID/helloworld).

Giờ đây, hình ảnh vùng chứa được lưu trữ trong Artifact Registry và có thể được dùng lại nếu muốn.

Xin lưu ý rằng thay vì Cloud Build, bạn có thể sử dụng phiên bản Docker được cài đặt cục bộ để tạo vùng chứa cục bộ.

Bước 3: Triển khai hình ảnh vùng chứa đến Cloud Run

  1. Triển khai bằng lệnh sau:

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

  2. Khi được nhắc:

  3. Chờ một lát để quá trình triển khai hoàn tất. Khi thành công, dòng lệnh sẽ hiển thị URL của dịch vụ. Ví dụ:https://helloworld-RANDOM_HASH-us-central1.a.run.app

  4. Truy cập vào vùng chứa đã triển khai bằng cách mở URL dịch vụ trong một trình duyệt web.

Bước tiếp theo sẽ hướng dẫn bạn cách truy cập vào ứng dụng được chứa trong vùng chứa này từ một Firebase HostingURL để ứng dụng có thể tạo nội dung động cho trang web được lưu trữ trên Firebase.

Bước 4: Chuyển trực tiếp các yêu cầu lưu trữ đến ứng dụng được đóng gói trong vùng chứa

Với quy tắc viết lại, bạn có thể chuyển các yêu cầu khớp với các mẫu cụ thể đến một đích đến duy nhất.

Ví dụ sau đây cho biết cách chuyển hướng tất cả các yêu cầu từ trang /helloworld trên trang web Hosting của bạn để kích hoạt quá trình khởi động và chạy phiên bản vùng chứa helloworld.

  1. Hãy đảm bảo rằng:

    Để biết hướng dẫn chi tiết về cách cài đặt CLI và khởi động Hosting, hãy xem Hướng dẫn bắt đầu sử dụng cho Hosting.

  2. Mở tệp firebase.json.

  3. Thêm cấu hình rewrite sau đây trong phần 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. Triển khai cấu hình lưu trữ cho trang web của bạn bằng cách chạy lệnh sau từ gốc của thư mục dự án:

    firebase deploy --only hosting

Giờ đây, bạn có thể truy cập vào vùng chứa của mình thông qua các URL sau:

  • Các miền phụ Firebase của bạn:
    PROJECT_ID.web.app/PROJECT_ID.firebaseapp.com/

  • Mọi miền tuỳ chỉnh được kết nối:
    CUSTOM_DOMAIN/

Truy cập vào trang cấu hình Hosting để biết thêm thông tin chi tiết về các quy tắc viết lại. Bạn cũng có thể tìm hiểu về thứ tự ưu tiên của các phản hồi cho nhiều cấu hình Hosting.

Kiểm thử cục bộ

Trong quá trình phát triển, bạn có thể chạy và kiểm thử hình ảnh vùng chứa cục bộ. Để biết hướng dẫn chi tiết, hãy truy cập vào tài liệu về Cloud Run.

Các bước tiếp theo