Cloud Run에 생성형 UI 웹사이트를 배포하는 방법

1. 소개

개요

이 실습에서는 Google의 Gemini 대규모 언어 모델이 즉석에서 콘텐츠를 생성하는 웹사이트를 빌드하고 배포합니다. 이 웹사이트는 주제를 탐색할 수 있는 간단한 '나만의 모험' 스타일 탐색기로, 클릭할 때마다 선택에 따라 새로운 링크가 포함된 새 페이지가 생성됩니다. Node.js와 Fastify를 사용하여 이를 빌드하고, Vertex AI SDK를 사용하여 Gemini를 호출하고, Cloud Run에 안전한 프로덕션 지원 서비스로 배포하고, IAP (Identity-Aware Proxy)를 사용하여 보호합니다.

실습할 내용

  • Vertex AI를 사용하는 Node.js Fastify 애플리케이션을 만듭니다.
  • Dockerfile 없이 소스에서 Cloud Run에 애플리케이션을 배포합니다.
  • IAP (Identity-Aware Proxy)를 사용하여 Cloud Run 엔드포인트를 보호합니다.

학습할 내용

  • Node.js용 Vertex AI SDK를 사용하여 콘텐츠를 생성하는 방법
  • Node.js 애플리케이션을 Cloud Run에 배포하는 방법
  • IAP로 Cloud Run 애플리케이션을 보호하는 방법

2. 프로젝트 설정

  1. 아직 Google 계정이 없다면 Google 계정을 만들어야 합니다.
    • 직장 또는 학교 계정 대신 개인 계정을 사용하세요. 직장 및 학교 계정에는 이 실습에 필요한 API를 사용 설정하지 못하도록 하는 제한이 있을 수 있습니다.
  2. Google Cloud 콘솔에 로그인합니다.
  3. Cloud 콘솔에서 결제를 사용 설정합니다.
    • 이 실습을 완료하는 데 드는 Cloud 리소스 비용은 미화 1달러 미만입니다.
    • 이 실습이 끝나면 단계에 따라 리소스를 삭제하여 추가 요금이 발생하지 않도록 할 수 있습니다.
    • 신규 사용자는 미화$300 상당의 무료 체험판을 사용할 수 있습니다.
  4. 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다.
    • 프로젝트 할당량에 관한 오류가 표시되면 기존 프로젝트를 재사용하거나 기존 프로젝트를 삭제하여 새 프로젝트를 만드세요.

3. Cloud Shell 편집기 열기

  1. 이 링크를 클릭하여 Cloud Shell 편집기로 바로 이동합니다.
  2. 오늘 언제든지 승인하라는 메시지가 표시되면 승인을 클릭하여 계속합니다. 클릭하여 Cloud Shell 승인
  3. 터미널이 화면 하단에 표시되지 않으면 다음 단계에 따라 엽니다.
    • 보기를 클릭합니다.
    • 터미널을 클릭합니다.Cloud Shell 편집기에서 새 터미널 열기
  4. 터미널에서 다음 명령어를 사용하여 프로젝트를 설정합니다.
    • 형식:
      gcloud config set project [PROJECT_ID]
      
    • 예:
      gcloud config set project lab-project-id-example
      
    • 프로젝트 ID를 기억할 수 없는 경우 다음 단계를 따르세요.
      • 다음 명령어를 사용하여 모든 프로젝트 ID를 나열할 수 있습니다.
        gcloud projects list | awk '/PROJECT_ID/{print $2}'
        
      Cloud Shell 편집기 터미널에서 프로젝트 ID 설정
  5. 다음 메시지가 표시되어야 합니다.
    Updated property [core/project].
    
    WARNING이 표시되고 Do you want to continue (Y/n)?라는 메시지가 표시되면 프로젝트 ID를 잘못 입력한 것일 수 있습니다. n를 누르고 Enter를 누른 후 gcloud config set project 명령어를 다시 실행해 보세요.
  1. GOOGLE_CLOUD_PROJECT 환경 변수를 설정합니다.
    export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
    

4. API 사용 설정

터미널에서 API를 사용 설정합니다.

gcloud services enable \
  run.googleapis.com \
  aiplatform.googleapis.com \
  cloudresourcemanager.googleapis.com \
  iap.googleapis.com

승인하라는 메시지가 표시되면 승인을 클릭하여 계속합니다. 클릭하여 Cloud Shell 승인

이 명령어를 완료하는 데 몇 분이 걸릴 수 있지만 결국 다음과 비슷한 성공 메시지가 표시됩니다.

Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.

5. Node.js 프로젝트 준비

  1. 배포할 소스 코드를 저장할 gen-ui-on-cloudrun이라는 폴더를 만듭니다.
    mkdir gen-ui-on-cloudrun && cd gen-ui-on-cloudrun
    
  2. Node.js 프로젝트를 초기화합니다.
    npm init -y
    
  3. 다음 명령어를 실행하여 ES 모듈을 사용하도록 프로젝트를 구성하고 시작 스크립트를 정의합니다.
    npm pkg set type="module"
    
  4. 웹 서버용 fastify와 Vertex AI SDK용 @google/genai를 설치합니다.
    npm install fastify @google/genai
    

6. 애플리케이션 코드 만들기

  1. 애플리케이션 소스 코드의 새 index.ts 파일을 만들고 엽니다.
    cloudshell edit ~/gen-ui-on-cloudrun/index.ts
    
    cloudshell edit 명령어를 사용하면 터미널 위의 편집기에서 index.ts 파일이 열립니다.
  2. 다음 생성형 UI 서버 소스 코드를 index.ts 파일에 추가합니다.
    import fastifyLib from 'fastify';
    import { GoogleGenAI } from '@google/genai';
    
    const fastify = fastifyLib({ logger: true });
    
    const ai = new GoogleGenAI({
        vertexai: true,
        project: process.env.GOOGLE_CLOUD_PROJECT,
        location: process.env.GOOGLE_CLOUD_LOCATION || 'europe-west1',
    });
    
    const SYSTEM_INSTRUCTION = `The user should have submitted an html page and the id of the element just clicked.
    Given the next page description, create a new webpage with a link back to "Start Over" (the / route), a brief overview of the topic, and a list of clickable link elements related to the page.
    When an element is clicked, the webpage should link to the base route / with the nextPageDescription as a query string parameter.
    All information needed to generate the next page should be included in the nextPageDescription without additional context.
    Each nextPageDescription should be less than 1500 characters.
    
    Example:
    If the current HTML page is for a small pet store, it might include a link to an "About" page.
    The href for the about page link should be /?nextPageDescription=about%20page%20for%20small%20pet%20store%20website
    
    All responses should be valid HTML without markdown backticks.`;
    
    interface QueryParams {
        nextPageDescription?: string;
    }
    
    fastify.get<{ Querystring: QueryParams }>('/', async (request, reply) => {
        const {
            nextPageDescription = 'A web page with interesting fun facts where I can select a fact to learn more about that topic.'
        } = request.query;
    
        try {
            const response = await ai.models.generateContent({
                model: 'gemini-2.5-flash',
                contents: nextPageDescription,
                config: {
                    systemInstruction: SYSTEM_INSTRUCTION,
                    temperature: 0.9,
                }
            });
    
            reply.type('text/html; charset=utf-8').send(response.text);
        } catch (error: any) {
            request.log.error(error);
            reply.status(500).send('An error occurred calling the AI.');
        }
    });
    
    const start = async () => {
        try {
            await fastify.listen({ port: Number(process.env.PORT) || 8080, host: '0.0.0.0' });
        } catch (err) {
            fastify.log.error(err);
            process.exit(1);
        }
    };
    
    start();
    

이 코드는 루트 경로 (/)에서 HTTP GET 요청을 수신하는 웹 서버를 설정합니다. 요청이 수신되면 Vertex AI를 통해 nextPageDescription 쿼리 매개변수 (또는 기본값)를 Gemini 2.5 Flash 모델의 프롬프트로 사용합니다. 모델은 SYSTEM_INSTRUCTION에 의해 링크가 포함된 HTML 페이지를 반환하도록 지시받으며, 각 링크에는 후속 페이지를 생성하기 위한 nextPageDescription가 포함됩니다.

7. 서비스 계정 만들기

Cloud Run 서비스가 Vertex AI API로 인증하려면 서비스 계정이 필요합니다.

  1. gen-navigator-sa라는 서비스 계정을 만듭니다.
    gcloud iam service-accounts create gen-navigator-sa --display-name="Generative Navigator Service Account"
    
  2. 서비스 계정에 Vertex AI 사용 권한을 부여합니다.
    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
        --member="serviceAccount:gen-navigator-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
        --role="roles/aiplatform.user"
    

8. Cloud Run에 배포

이제 Dockerfile 없이 소스 코드에서 직접 Cloud Run에 애플리케이션을 배포합니다.

  1. gcloud 명령어를 실행하여 애플리케이션을 배포합니다.
    cd ~/gen-ui-on-cloudrun
    gcloud beta run deploy generative-web-navigator \
        --source . \
        --no-build \
        --base-image=nodejs24 \
        --command="node" \
        --args="index.ts" \
        --region=europe-west1 \
        --no-allow-unauthenticated \
        --iap \
        --service-account="gen-navigator-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
        --set-env-vars GOOGLE_CLOUD_PROJECT="$GOOGLE_CLOUD_PROJECT",GOOGLE_CLOUD_LOCATION="europe-west1"
    
    여기에서는 몇 가지 중요한 플래그를 사용합니다.
    • --source . --no-build --base-image=nodejs24: Cloud Run에 현재 디렉터리의 소스 코드를 배포하고, 빌드 단계를 건너뛰고, 사전 빌드된 Node.js 24 기본 이미지를 사용하여 애플리케이션을 실행하도록 지시합니다.
    • --no-allow-unauthenticated: 이렇게 하면 인증된 사용자만 서비스에 액세스할 수 있습니다.
    • --iap: IAP (Identity-Aware Proxy)가 애플리케이션에 대한 액세스를 관리할 수 있도록 합니다. IAP를 사용하면 IP 주소뿐만 아니라 사용자 ID와 컨텍스트를 기반으로 액세스를 제어할 수 있습니다.
  2. 몇 분 후 다음과 같은 메시지가 표시됩니다.
    Service [generative-web-navigator] revision [generative-web-navigator-12345-abc] has been deployed and is serving 100 percent of traffic.
    

애플리케이션을 배포했지만 액세스를 허용하려면 IAP를 구성해야 합니다.

9. IAP 액세스 구성

Cloud Run에서 IAP를 사용 설정하면 IAP가 모든 요청을 가로채고 사용자가 서비스에 도달하기 전에 인증 및 승인을 받아야 합니다. 이 기능을 사용하려면 다음 두 가지 권한을 부여해야 합니다.

  • IAP 서비스 자체에서 Cloud Run 서비스를 호출하도록 허용합니다.
  • 본인 (또는 다른 사용자/그룹)이 IAP를 통해 애플리케이션에 액세스하도록 허용합니다.
  1. IAP 서비스 에이전트를 식별하는 데 필요한 프로젝트 번호를 가져옵니다.
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    
  2. Cloud Run 서비스에서 IAP 서비스 에이전트에 roles/run.invoker 역할을 부여합니다. 이를 통해 IAP는 사용자를 인증하고 승인한 후 서비스를 호출할 수 있습니다.
    gcloud run services add-iam-policy-binding generative-web-navigator \
        --region=europe-west1 \
        --member="serviceAccount:service-$PROJECT_NUMBER@gcp-sa-iap.iam.gserviceaccount.com" \
        --role="roles/run.invoker"
    
  3. 사용자 계정에 roles/iap.httpsResourceAccessor 역할을 부여합니다. 이를 통해 IAP 보안 HTTPS 리소스에 액세스할 수 있습니다.
    gcloud beta iap web add-iam-policy-binding \
        --resource-type=cloud-run \
        --region=europe-west1 \
        --service=generative-web-navigator \
        --member="user:$(gcloud config get-value account)" \
        --role="roles/iap.httpsResourceAccessor"
    

10. 애플리케이션 테스트

  1. 배포된 서비스의 URL을 가져옵니다.
    gcloud run services describe generative-web-navigator --format='value(status.url)' --region=europe-west1
    
  2. URL을 복사하여 웹브라우저에서 엽니다. 서비스가 IAP로 보호되므로 아직 로그인하지 않은 경우 Google 계정으로 로그인하라는 메시지가 표시됩니다. 인증 후 첫 번째 자동 생성 페이지가 표시됩니다.
  3. 링크를 클릭하여 새 페이지로 이동합니다. 클릭한 링크를 기반으로 AI가 새 페이지를 생성합니다.

완료했습니다. 생성형 UI 웹사이트를 Cloud Run에 배포하고 IAP를 사용하여 보호했습니다.

11. 결론

축하합니다. Cloud Run, Vertex AI, IAP를 사용하여 생성형 UI 웹사이트를 배포하고 보호했습니다.

(선택사항) 정리

생성한 항목을 정리하려면 Cloud 프로젝트를 삭제하여 추가 요금이 발생하지 않도록 하면 됩니다.

Cloud Run에서는 서비스를 사용하지 않을 때 비용이 청구되지 않지만 빌드 아티팩트가 생성된 경우 이를 저장하는 데 요금이 부과될 수 있습니다. Cloud 프로젝트를 삭제하면 해당 프로젝트 내에서 사용되는 모든 리소스에 대한 청구가 중단됩니다.

원하는 경우 프로젝트를 삭제합니다.

gcloud projects delete $GOOGLE_CLOUD_PROJECT

cloudshell 디스크에서 불필요한 리소스를 삭제하는 것이 좋습니다. 다음과 같은 작업을 할 수 있습니다.

  1. Codelab 프로젝트 디렉터리를 삭제합니다.
    rm -rf ~/gen-ui-on-cloudrun
    
  2. 경고 이 작업은 실행취소할 수 없습니다. 공간을 확보하기 위해 Cloud Shell의 모든 항목을 삭제하려면 전체 홈 디렉터리를 삭제하면 됩니다. 보관하려는 모든 항목이 다른 곳에 저장되어 있는지 확인하세요.
    sudo rm -rf $HOME