Firebase Summit에서 발표된 모든 내용을 살펴보고 Firebase로 앱을 빠르게 개발하고 안심하고 앱을 실행하는 방법을 알아보세요. 자세히 알아보기

Cloud Run으로 동적 콘텐츠 제공 및 마이크로서비스 호스팅

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

Cloud Run을 Firebase 호스팅과 페어링하여 동적 콘텐츠를 생성 및 제공하거나 REST API를 마이크로서비스로 구축하세요.

Cloud Run 을 사용하면 컨테이너 이미지에 패키징된 애플리케이션을 배포할 수 있습니다. 그런 다음 Firebase 호스팅을 사용하여 HTTPS 요청을 지시하여 컨테이너화된 앱을 트리거할 수 있습니다.

  • Cloud Run은 여러 언어 (Go, Node.js, Python, Java 포함)를 지원하므로 선택한 프로그래밍 언어와 프레임워크를 유연하게 사용할 수 있습니다.
  • Cloud Run은 수신된 요청을 처리하기 위해 컨테이너 이미지를 자동으로 수평으로 확장 한 다음 수요가 감소하면 축소합니다.
  • 요청 처리 중에 소비된 CPU, 메모리 및 네트워킹에 대해서만 비용을 지불 합니다.

Firebase 호스팅과 통합된 Cloud Run의 사용 사례 및 샘플 예는 서버리스 개요 를 참조하세요.


이 가이드에서는 다음을 수행하는 방법을 보여줍니다.

  1. 간단한 Hello World 애플리케이션 작성
  2. 앱 컨테이너화 및 Container Registry에 업로드
  3. Cloud Run에 컨테이너 이미지 배포
  4. 컨테이너화된 앱에 대한 직접 호스팅 요청

동적 콘텐츠 제공 성능을 개선하기 위해 선택적으로 캐시 설정 을 조정할 수 있습니다.

시작하기 전에

Cloud Run을 사용하기 전에 Cloud Billing 계정 설정, Cloud Run API 사용 설정, gcloud 명령줄 도구 설치를 포함한 몇 가지 초기 작업을 완료해야 합니다.

프로젝트에 대한 결제 설정

Cloud Run은 무료 사용 할당량 을 제공하지만 Cloud Run을 사용하거나 사용해 보려면 Firebase 프로젝트와 연결된 Cloud Billing 계정 이 있어야 합니다.

API 활성화 및 SDK 설치

  1. Google API 콘솔에서 Cloud Run API를 사용 설정합니다.

    1. Google API 콘솔에서 Cloud Run API 페이지 를 엽니다.

    2. 메시지가 표시되면 Firebase 프로젝트를 선택합니다.

    3. Cloud Run API 페이지에서 사용 을 클릭합니다.

  2. Cloud SDK 를 설치하고 초기화 합니다.

  3. 올바른 프로젝트에 대해 gcloud 도구가 구성되었는지 확인합니다.

    gcloud config list

1단계 : 샘플 애플리케이션 작성

Cloud Run은 다음 샘플에 표시된 언어 외에도 많은 다른 언어 를 지원합니다.

가다

  1. helloworld-go 라는 새 디렉터리를 만든 다음 디렉터리를 여기로 변경합니다.

    mkdir helloworld-go
    cd helloworld-go
  2. helloworld.go 라는 새 파일을 만들고 다음 코드를 추가합니다.

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

    이 코드는 PORT 환경 변수에 의해 정의된 포트에서 수신 대기하는 기본 웹 서버를 생성합니다.

앱이 완료되었으며 컨테이너화되어 Container Registry에 업로드될 준비가 되었습니다.

Node.js

  1. helloworld-nodejs 라는 새 디렉터리를 만든 다음 디렉터리를 여기로 변경합니다.

    mkdir helloworld-nodejs
    cd helloworld-nodejs
  2. 다음 내용으로 package.json 파일을 만듭니다.

    {
      "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.18.2"
      }
    }
    
  3. index.js 라는 새 파일을 만들고 다음 코드를 추가합니다.

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

    이 코드는 PORT 환경 변수에 의해 정의된 포트에서 수신 대기하는 기본 웹 서버를 생성합니다.

앱이 완료되었으며 컨테이너화되어 Container Registry에 업로드될 준비가 되었습니다.

파이썬

  1. helloworld-python 이라는 이름의 새 디렉터리를 만든 다음 디렉터리를 여기로 변경합니다.

    mkdir helloworld-python
    cd helloworld-python
  2. app.py 라는 새 파일을 만들고 다음 코드를 추가합니다.

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

    이 코드는 PORT 환경 변수에 의해 정의된 포트에서 수신 대기하는 기본 웹 서버를 생성합니다.

앱이 완료되었으며 컨테이너화되어 Container Registry에 업로드될 준비가 되었습니다.

자바

  1. Java SE 8 이상 JDKCURL 을 설치합니다.

    다음 단계에서 새 웹 프로젝트를 생성하기 위해서만 이 작업을 수행하면 됩니다. 나중에 설명하는 Dockerfile은 모든 종속성을 컨테이너에 로드합니다.

  2. 콘솔에서 cURL을 사용하여 새로운 빈 웹 프로젝트를 만든 다음 압축을 풉니다.

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

    이렇게 하면 SpringBoot 프로젝트가 생성됩니다.

  3. / 매핑을 처리하는 @RestController 를 추가하여 src/main/java/com/example/helloworld/HelloworldApplication.java 에서 SpringBootApplication 클래스를 업데이트하고 TARGET 환경 변수를 제공하는 @Value 필드도 추가합니다.

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

    이 코드는 PORT 환경 변수에 의해 정의된 포트에서 수신 대기하는 기본 웹 서버를 생성합니다.

앱이 완료되었으며 컨테이너화되어 Container Registry에 업로드될 준비가 되었습니다.

2단계 : 앱 컨테이너화 및 Container Registry에 업로드

  1. 소스 파일과 동일한 디렉터리에 Dockerfile 이라는 새 파일을 만들어 샘플 앱을 컨테이너화합니다. 다음 콘텐츠를 파일에 복사합니다.

    가다

    # Use the official Golang image to create a build artifact.
    # This is based on Debian and sets the GOPATH to /go.
    FROM golang:1.13 as builder
    
    # 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=linux 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" ]
    

    파이썬

    # 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
    

    자바

    # 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. Dockerfile이 포함된 디렉터리에서 다음 명령어를 실행하여 Cloud Build를 사용하여 컨테이너 이미지를 빌드합니다.

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

    성공하면 이미지 이름이 포함된 SUCCESS 메시지가 표시됩니다.
    ( gcr.io/ PROJECT_ID /helloworld ).

컨테이너 이미지는 이제 Container Registry에 저장되며 원하는 경우 재사용할 수 있습니다.

Cloud Build 대신 로컬에 설치된 Docker 버전을 사용하여 로컬에서 컨테이너를 빌드할 수 있습니다 .

3단계 : Cloud Run에 컨테이너 이미지 배포

  1. 다음 명령을 사용하여 배포합니다.

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

  2. 메시지가 표시되면:

  3. 배포가 완료될 때까지 잠시 기다립니다. 성공하면 명령줄에 서비스 URL이 표시됩니다. 예: https://helloworld- RANDOM_HASH -us-central1.a.run.app

  4. 웹 브라우저에서 서비스 URL을 열어 배포된 컨테이너를 방문합니다.

다음 단계 에서는 Firebase 호스팅 URL에서 이 컨테이너화 된 앱에 액세스하여 Firebase 호스팅 사이트에 대한 동적 콘텐츠를 생성할 수 있도록 하는 방법을 안내합니다.

4단계: 컨테이너화된 앱에 대한 직접 호스팅 요청

재작성 규칙 을 사용하면 특정 패턴과 일치하는 요청을 단일 대상으로 보낼 수 있습니다.

다음 예는 호스팅 사이트의 /helloworld 페이지에서 모든 요청을 지시하여 helloworld 컨테이너 인스턴스의 시작 및 실행을 트리거하는 방법을 보여줍니다.

  1. 다음을 확인하십시오.

    CLI 설치 및 호스팅 초기화에 대한 자세한 지침은 호스팅 시작 안내서를 참조하십시오.

  2. firebase.json 파일 을 엽니다.

  3. hosting 섹션 아래에 다음 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)
        }
      } ]
    }
    
  4. 프로젝트 디렉터리의 루트에서 다음 명령을 실행하여 사이트에 호스팅 구성을 배포합니다.

    firebase deploy

이제 다음 URL을 통해 컨테이너에 연결할 수 있습니다.

  • Firebase 하위 도메인:
    PROJECT_ID .web.app/PROJECT_ID .firebaseapp.com/

  • 연결된 사용자 지정 도메인 :
    CUSTOM_DOMAIN /

재작성 규칙에 대한 자세한 내용은 호스팅 구성 페이지를 참조하십시오. 다양한 호스팅 구성 에 대한 응답의 우선 순위 에 대해서도 알아볼 수 있습니다.

로컬에서 테스트

개발 중에 컨테이너 이미지를 로컬에서 실행하고 테스트할 수 있습니다. 자세한 안내는 Cloud Run 문서 를 참조하세요.

다음 단계