Cloud DNS를 사용하여 작업자 풀의 비공개 IP 주소 등록

이 튜토리얼에서는 Cloud DNS 관리형 영역 내에서 Cloud Run 작업자 풀 인스턴스의 비공개 IP 주소를 등록하는 방법을 설명합니다. 이 튜토리얼에서는 시작 스크립트를 사용하여 메타데이터 서버를 통해 인스턴스 IP를 동적으로 감지하고 VPC 네트워크 내에서 직접 수신을 처리하는 Node.js 애플리케이션을 만듭니다.

목표

비용

이 문서에서는 비용이 청구될 수 있는 구성요소를 사용합니다 Google Cloud.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요.

Google Cloud 신규 사용자는 무료 체험판을 사용할 수 있습니다.

시작하기 전에

  1. 계정에 로그인합니다. Google Cloud 를 처음 사용하는 경우 Google Cloud 계정을 만들어 실제 시나리오에서 제품이 어떻게 작동하는지 평가하세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  5. Verify that billing is enabled for your Google Cloud project.

  6. Cloud DNS, Cloud Run, Compute Engine, Artifact Registry, Cloud Build API를 사용 설정합니다.

    API 사용 설정에 필요한 역할

    API를 사용 설정하려면 serviceusage.services.enable 권한이 포함된 서비스 사용량 관리자 IAM 역할(roles/serviceusage.serviceUsageAdmin)이 필요합니다. 역할 부여 방법 알아보기.

    API 사용 설정

  7. gcloud CLI를 설치하고 초기화합니다.
  8. 구성요소를 업데이트합니다.
    gcloud components update
  9. 다음 명령어를 실행하여 프로젝트 ID를 설정합니다.
    gcloud config set project PROJECT_ID
    PROJECT_ID를 프로젝트 ID로 바꿉니다. Google Cloud

필요한 역할

튜토리얼을 완료하는 데 필요한 권한을 얻으려면 관리자에게 프로젝트에 대한 다음 IAM 역할을 부여해 달라고 요청하세요.

역할 부여에 대한 자세한 내용은 프로젝트, 폴더, 조직에 대한 액세스 관리를 참조하세요.

커스텀 역할이나 다른 사전 정의된 역할을 통해 필요한 권한을 얻을 수도 있습니다.

커스텀 서비스 계정 만들기

DNS 레코드를 등록하는 데 필요한 최소 권한으로 커스텀 서비스 계정을 만듭니다. 서비스 계정을 설정하려면 다음 단계를 따르세요.

  1. 다음 명령어를 실행하여 서비스 계정을 만듭니다.

    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME \
      --display-name="DNS Worker Pool Service Account"

    SERVICE_ACCOUNT_NAME을 커스텀 서비스 계정의 이름(예: dns-worker-sa)으로 바꿉니다.

  2. 서비스 계정에 Cloud DNS 관리자 역할을 부여합니다.

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member="serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com" \
      --role="roles/dns.admin"

Cloud DNS 영역 만들기

test-wp라는 비공개 Cloud DNS 관리형 영역을 만들어 작업자 풀의 인스턴스 IP를 등록합니다.

gcloud dns managed-zones create test-wp --description="new DNS zone for worker pools"  --dns-name="workerpools.example.com."  --visibility="private" --networks=default

Node.js 애플리케이션 만들기

메타데이터 서버를 사용하여 작업자 풀 인스턴스의 IP 주소를 가져온 후 Cloud DNS에 등록하는 Node.js 애플리케이션을 만듭니다.

  1. worker라는 폴더를 만들고 디렉터리를 변경합니다.

    mkdir worker
    cd worker
    
  2. setup_dns.sh라는 파일을 만들고 작업자 풀 인스턴스가 시작될 때 실행되는 다음 스크립트를 추가합니다. 이 스크립트는 인스턴스 호스트 이름을 사용하여 DNS 레코드 이름을 생성합니다. 인스턴스가 두 개 이상인 경우 여러 인스턴스에서 동일한 호스트 이름을 사용하여 DNS 레코드가 겹칠 수 있습니다.

    #!/bin/bash
    
    # --- Variables ---
    # The name of your Cloud DNS managed zone.
    ZONE_NAME="test-wp"
    # The base domain suffix for the DNS entry. Use the part *after* the hostname.
    # For example, for "testinstance.workerpools.example.com.", the suffix is ".workerpools.example.com."
    DNS_SUFFIX=".workerpools.example.com."
    # The Time-To-Live (TTL) in seconds.
    TTL="300"
    # The record type (A for IPv4).
    RECORD_TYPE="A"
    # -----------------
    
    # 1. Dynamically generate DNS_NAME
    # Get the simple hostname (e.g., "testinstance") and append the defined suffix.
    # We use 'hostname -s' to get the short hostname.
    SHORT_HOSTNAME=$(hostname -s)
    DNS_NAME="${SHORT_HOSTNAME}${DNS_SUFFIX}"
    
    # 2. Dynamically assign NEW_IP
    # Get the IP address from metadata server using predefined key.
    NEW_IP=$(curl "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip" -H "Metadata-Flavor: Google")
    
    # --- Input Validation ---
    if [ -z "$NEW_IP" ]; then
        echo "❌ ERROR: Could not obtain a valid IP address from metadata server. Aborting."
        exit 1
    fi
    
    echo "Starting DNS record update for ${DNS_NAME} in zone ${ZONE_NAME}..."
    echo "New IP detected on this instance: ${NEW_IP}"
    
    # 3. Get the current existing IP address (if any)
    # This is required to know what to put in the --rrdatas for the delete command.
    EXISTING_IP=$(gcloud dns record-sets list \
        --zone="${ZONE_NAME}" \
        --name="${DNS_NAME}" \
        --type="${RECORD_TYPE}" \
        --format="value(rrdatas[0])" 2>/dev/null)
    
    # --- Conditional Deletion/Skip Check ---
    if [ -n "$EXISTING_IP" ] && [ "$EXISTING_IP" != "$NEW_IP" ]; then
        echo "Found existing IP: ${EXISTING_IP}. It is different from the new IP."
    
        # Delete the existing record
        echo "Deleting old record..."
        gcloud dns record-sets delete "${DNS_NAME}" \
            --zone="${ZONE_NAME}" \
            --type="${RECORD_TYPE}" \
            --quiet
    
        if [ $? -ne 0 ]; then
            echo "❌ ERROR: Failed to delete existing record. Aborting."
            exit 1
        fi
    elif [ -n "$EXISTING_IP" ] && [ "$EXISTING_IP" == "$NEW_IP" ]; then
        echo "Existing IP (${EXISTING_IP}) matches the new IP. Skipping update."
        exit 0
    else
        echo "No existing record found for ${DNS_NAME}. Proceeding with creation."
    fi
    # ----------------------------------------
    
    # 4. Add the new record
    echo "Creating new record with IP: ${NEW_IP}..."
    gcloud dns record-sets create "${DNS_NAME}" \
      --zone="${ZONE_NAME}" \
      --type="${RECORD_TYPE}" \
      --ttl="${TTL}" \
      --rrdatas="${NEW_IP}"
    
    # Final status check
    if [ $? -eq 0 ]; then
        echo "✅ Successfully created/updated DNS record for ${DNS_NAME} to ${NEW_IP}."
    else
        echo "❌ ERROR: Failed to create the new DNS record."
        exit 1
    fi
    
  3. 다음 코드를 사용하여 비공개 IP 주소 수신을 처리하는 server.js 파일을 만듭니다.

    // server.js
    
    // 1. Import the built-in 'http' module
    console.log("hello from worker pool")
    const http = require('http');
    
    // Define the port the server will listen on
    const PORT = 3000;
    
    // 2. Create the server instance
    const server = http.createServer((req, res) => {
      // Set the response HTTP header with status and type of content
      res.writeHead(200, {'Content-Type': 'text/plain'});
      // Write the response body
      res.end('Hello World!\n');
    });
    
    // 3. Start the server and listen on the specified port
    server.listen(PORT, () => {
      console.log(`Server running at http://localhost:${PORT}/`);
    });
    
  4. Node.js 애플리케이션을 실행하기 전에 먼저 DNS 설정을 실행하는 다음 코드를 사용하여 start.sh 스크립트를 만듭니다.

    #!/bin/bash
    set -e
    
    # 1. Execute the setup script
    echo "Running setup_dns.sh..."
    /app/setup_dns.sh
    
    # 2. Run the main application
    echo "Starting server.js..."
    exec node /app/server.js
    
  5. 다음 Dockerfile을 만들어 애플리케이션을 이미지로 패키징합니다.

    # Choose a base image. This image includes gcloud, kubectl, etc.
    FROM google/cloud-sdk:latest
    
    # Install Node.js on top of the Cloud SDK image.
    RUN apt-get update && \
        apt-get install -y curl && \
        curl -sL https://deb.nodesource.com/setup_lts.x | bash - && \
        apt-get install -y nodejs && \
        # Clean up to reduce image size
        apt-get clean && \
        rm -rf /var/lib/apt/lists/*
    
    # Set the working directory inside the container.
    WORKDIR /app
    
    # Copy the application and scripts into the container.
    COPY setup_dns.sh .
    COPY server.js .
    COPY start.sh .
    
    # Make both scripts executable.
    RUN chmod +x setup_dns.sh start.sh
    
    # Define the entrypoint and default command.
    ENTRYPOINT ["/app/start.sh"]
    CMD []
    

직접 VPC 수신으로 작업자 풀 배포

test-cli-dns라는 작업자 풀을 배포하고 VPC 네트워크에 연결합니다.

gcloud beta run worker-pools deploy test-cli-dns \
  --network default \
  --subnet default \
  --region us-central1 \
  --source . \
  --service-account SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
  --project PROJECT_ID

PROJECT_ID를 프로젝트 ID로 바꾸고 SERVICE_ACCOUNT_NAME을 만든 서비스 계정의 이름으로 바꿉니다. Google Cloud

애플리케이션 테스트

직접 VPC 수신이 있는 Cloud Run 작업자 풀은 내부 전용 트래픽을 위해 설계되었습니다. 공개 IP가 없습니다. 수신 기능을 확인하려면 다음 단계에 따라 동일한 VPC 네트워크 및 서브넷에서 호스팅되는 Compute Engine VM에서 curl을 사용하여 요청을 실행합니다.

  1. 작업자 풀과 동일한 네트워크 및 리전에 테스트 VM을 만듭니다.

     gcloud compute instances create wp-test-vm \
         --zone=us-central1-a \
         --network=default \
         --subnet=default
    
  2. 다음 명령어를 실행하여 SSH를 통해 테스트 VM에 연결합니다.

     gcloud compute ssh wp-test-vm --zone=us-central1-a
    
  3. VM 터미널에서 Cloud DNS에 등록된 작업자 풀 인스턴스의 비공개 IP 주소에서 서비스를 호출합니다.

    curl http://localhost.workerpools.example.com:3000

    다음 출력이 표시됩니다.

    Hello World!

완료 비공개 IP 주소와 Cloud DNS를 사용하여 직접 VPC 수신으로 Cloud Run 작업자 풀을 구성했습니다.

삭제

Google Cloud 계정에 추가 비용이 청구되지 않게 하려면 이 튜토리얼에서 배포한 모든 리소스를 삭제합니다.

프로젝트 삭제

이 튜토리얼용으로 새 프로젝트를 만든 경우 이 프로젝트를 삭제합니다. 기존 프로젝트를 사용했고 이 튜토리얼에 추가된 변경사항을 제외하고 보존하려면 튜토리얼을 위해 만든 리소스를 삭제합니다.

비용이 청구되지 않도록 하는 가장 쉬운 방법은 튜토리얼에서 만든 프로젝트를 삭제하는 것입니다.

프로젝트를 삭제하는 방법은 다음과 같습니다.

  1. 콘솔에서 리소스 관리 페이지로 이동합니다. Google Cloud

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료 를 클릭하여 프로젝트를 삭제합니다.

튜토리얼 리소스 삭제

  1. 이 튜토리얼에서 배포한 Cloud Run 서비스를 삭제합니다. Cloud Run 서비스는 요청을 수신할 때까지 비용을 청구하지 않습니다.

    Cloud Run 서비스를 삭제하려면 다음 명령어를 실행합니다.

    gcloud run services delete SERVICE-NAME

    SERVICE-NAME를 서비스 이름으로 바꿉니다.

    Google Cloud 콘솔에서 Cloud Run 서비스를 삭제할 수도 있습니다.

  2. 튜토리얼 설정 중에 추가한 gcloud 기본 리전 구성을 삭제합니다.

     gcloud config unset run/region
    
  3. 프로젝트 구성을 삭제합니다.

     gcloud config unset project
    
  4. 이 튜토리얼에서 만든 다른 Google Cloud 리소스를 삭제합니다.

다음 단계