Bokeh와 BigQuery로 커스텀 대화형 대시보드 만들기

이 튜토리얼에서는 Bokeh 라이브러리를 사용하여 공개적으로 사용 가능한 BigQuery 데이터 세트의 데이터를 시각화하여 Google Cloud에서 커스텀 대화형 대시보드 앱을 빌드하는 방법을 알아봅니다. 또한 보안과 확장성을 염두에 두고 이 앱을 배포하는 방법 또한 알아봅니다.

Google 데이터 스튜디오와 같은 강력한 서비스로서의 소프트웨어(SaaS) 솔루션은 대화형 데이터 시각화 대시보드를 빌드할 때 매우 유용합니다. 하지만 이러한 유형의 솔루션은 충분한 커스텀 옵션을 제공하지 않을 수 있습니다. 이러한 시나리오의 경우 D3.js, Chart.js, Bokeh와 같은 오픈소스 라이브러리를 사용하여 커스텀 대시보드를 만들 수 있습니다. 이러한 라이브러리는 맞춤형 기능과 시각화를 통해 대시보드 빌드에 높은 유연성을 제공하지만, 이해관계자가 간편하게 액세스할 수 있도록 이러한 대시보드를 인터넷에 배포해야 하는 문제점이 남아 있습니다.

목표

  • Bokeh를 사용하여 빌드한 커스텀 앱에서 BigQuery에 연결하는 방법을 알아봅니다.
  • Memcached를 사용하여 병렬 쿼리와 앱 수준 캐싱 등의 최적화 기술을 구현합니다.
  • Kubernetes를 사용하여 대시보드 데모를 Google Kubernetes Engine(GKE)에 배포합니다.
  • HTTPS 부하 분산기를 만듭니다.
  • CDN을 사용하는 백엔드를 배포하여 정적 애셋을 제공합니다.
  • IAP(Identity-Aware Proxy) 인증 및 SSL 암호화를 사용하여 앱을 보호합니다.

비용

이 가이드에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

  • BigQuery
  • Compute Engine
  • Cloud Storage
  • Cloud CDN
  • 부하 분산기
  • 고정 IP 주소

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

시작하기 전에

  1. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  2. Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요.

  3. GKE and BigQuery API를 사용 설정합니다.

    API 사용 설정

  4. Cloud Shell 인스턴스를 시작합니다. 이 튜토리얼 전체에서 Cloud Shell을 사용합니다.

    Cloud Shell 열기

  5. Cloud Shell에서 다음 명령을 실행하여 GitHub 저장소를 복제합니다.

    git clone https://github.com/GoogleCloudPlatform/bigquery-bokeh-dashboard
  6. Cloud Shell에서 기본 Compute Engine 영역을 GKE 클러스터를 생성할 영역으로 설정합니다. 이 튜토리얼에서는 us-central1-a 영역을 사용합니다.

    gcloud config set compute/zone us-central1-a
  7. 데모 앱이 BigQuery에 액세스할 수 있도록 다음 명령을 실행하여 서비스 계정 키를 만듭니다.

    export PROJECT_ID=$(gcloud info --format='value(config.project)')
    export SERVICE_ACCOUNT_NAME="dashboard-demo"
    cd bigquery-bokeh-dashboard
    gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \
        --display-name="Bokeh/BigQuery Dashboard Demo"
    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
        --role roles/bigquery.user
    gcloud iam service-accounts keys create --iam-account \
        "${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
        service-account-key.json
          

    서비스 계정에 대한 자세한 내용은 서비스 계정을 참조하세요.

데모 앱 이해

데모 앱에는 미국 50개 주 전체에서 공개적으로 사용 가능한 데이터를 처리하고 시각화하는 대시보드가 표시됩니다. 대시보드는 간단한 수준의 상호작용을 제공합니다. 사용자는 드롭다운 위젯에서 50개의 주 중 하나를 선택하여 해당 주에 대한 정보를 상세하게 보고 표시할 수 있습니다. 대시보드에는 4가지 모듈이 있으며 각 모듈에는 다양한 유형의 정보가 표시되어 있습니다.

실행 중인 데모의 스크린샷은 다음과 같습니다.

그래프를 사용한 앱의 대시보드 뷰

전체 아키텍처

대략적으로 데모의 아키텍처는 6개의 주요 요소로 구성됩니다. 다음 다이어그램은 이러한 구성요소의 상호작용 방식을 보여줍니다.

데모 앱의 아키텍처

이러한 요소는 다음과 같습니다.

  • 대시보드 사용자의 데스크톱 컴퓨터 및 휴대기기의 클라이언트 웹브라우저
  • IAP에서 관리하며 앱 액세스를 제어하는 인증 프록시
  • 수신된 웹 트래픽을 적절한 백엔드에 분산하고 시스템에서 송수신하는 데이터의 SSL 복호화/암호화를 효과적으로 처리하는 HTTPS 부하 분산기
  • 대시보드의 동적 콘텐츠(HTML 및 데이터 그래프)를 제공하는 앱 백엔드 이 앱 백엔드는 GitHub에 제공되는 Dockerfile로 빌드된 Docker 이미지를 사용합니다. 사용자의 이미지를 사용할 수 있지만 이 단계는 이 튜토리얼에서 다루지 않습니다.
  • 클라이언트 웹브라우저 렌더링에 필요한 정적 자바스크립트 및 CSS 파일을 제공하는 정적 애셋 백엔드

앱 백엔드

앱 백엔드는 부하 분산기에서 수신되는 요청을 받은 다음 BigQuery에서 적절한 데이터를 검색하여 변환합니다. 백엔드는 요청된 동적 콘텐츠를 HTTP를 통해 HTML 형식으로 반환하고 WebSocket을 통해 데이터 그래프를 반환합니다.

다음 다이어그램은 이러한 아키텍처를 보여줍니다.

앱의 백엔드 아키텍처

앱 백엔드에는 2개의 주요 하위 구성요소가 있습니다.

  • Bokeh 서비스. 앱의 핵심 요소인 이 서비스에는 BigQuery에서 데이터를 쿼리하고 클라이언트 웹브라우저에서 사용할 동적 콘텐츠를 생성하는 Bokeh 서버를 실행하는 포드가 포함됩니다.
  • Memcached 서비스. 자주 요청되는 데이터를 캐시하는 Memcached 서버를 실행하는 pod가 포함됩니다.

이러한 하위 구성요소는 Docker 컨테이너에 존재하고 Kubernetes pod로서 Kubernetes Engine에 배포되어 수평적 확장성을 제공합니다.

Bokeh 서비스

이 데모에서 Bokeh 서비스에는 2개의 Bokeh 포드가 포함되어 있습니다. 각 포드는 Tornado의 비차단형 웹 서버를 둘러싼 래퍼인 별도의 Bokeh 서버 인스턴스를 실행합니다. 이 서버는 HTML 콘텐츠의 정보는 HTTP를 통해 동기적으로, 대시보드 데이터 그래프의 정보는 Websocket을 통해 비동기적으로 제공합니다.

이 튜토리얼에서 각 Bokeh 서버는 4개의 작업 하위 프로세스로 포크되도록 구성되었으며, 이는 컨테이너 DockerfileCMD 문 내의 --num-procs 매개변수가 나타냅니다.

CMD bokeh serve --disable-index-redirect --num-procs=4 --port=5006 --address=0.0.0.0 --allow-websocket-origin=$DASHBOARD_DEMO_DOMAIN dashboard.py

Bokeh 서버는 하위 프로세스 간에 수신 트래픽의 부하를 자동으로 분산합니다. 이 접근 방식을 사용하면 각 포드의 성능과 복원력이 향상됩니다. 이 튜토리얼에서 사용하는 하위 프로세스의 수는 임의적입니다. 실제 시나리오에서는 실제 프로덕션 트래픽과 클러스터에서 사용 가능한 메모리 및 CPU 리소스에 따라 이 수를 조정하세요.

BigQuery는 read_gbq 메서드를 사용하여 Bokeh 앱에서 직접 액세스할 수 있습니다. 자세한 내용은 Pandas 라이브러리의 gbq 확장 프로그램에서 read_gbq 메서드 관련 문서를 참조하세요. 이 메서드는 매우 간단한 인터페이스를 가지고 있으며 쿼리를 매개변수로 허용하고 네트워크를 통해 이를 BigQuery에 제출합니다. 기타 필요한 매개변수에는 프로젝트 ID와 서비스 계정 키가 있으며, 둘 다 GKE 비밀번호로 로드한 환경 변수를 통해 전달할 수 있습니다. 그러면 read_gbq 메서드는 BigQuery에서 반환한 결과를 투명하게 페이지로 나눈 다음 Bokeh가 직접 처리할 수 있는 단일 Pandas DataFrame 객체로 통합합니다.

예를 들어 read_gbq를 통해 제출되어 캘리포니아 주(주 코드 'CA')에서 인구가 가장 많은 우편번호 100개를 수집하는 쿼리의 예시는 다음과 같습니다.

query = """
    SELECT
      A.zipcode,
      Population,
      City,
      State_code
    FROM
      `bigquery-public-data.census_bureau_usa.population_by_zip_2010` AS A
    JOIN
      `bigquery-public-data.utility_us.zipcode_area` AS B
    ON
     A.zipcode = B.zipcode
    WHERE
     gender = ''
    AND
     state_code = '%(state)s'
    ORDER BY
     population DESC
    LIMIT
     100
"""

import os
import pandas
dataframe = pandas.io.gbq.read_gbq(
   query % 'CA',
   project_id=os.environ['GOOGLE_PROJECT_ID'],
   private_key=os.environ['GOOGLE_APPLICATION_CREDENTIALS'],
   dialect='standard'
)

결과 데이터를 네트워크를 통해 전달해야 하기 때문에 가능한 한 많은 양의 사전 처리를 BigQuery에 오프로드하는 것이 좋습니다. 예를 들어 전체 네트워크 트래픽을 줄이고 응답 시간을 단축하기 위해 LIMIT 절을 사용하거나, SELECT 절의 필드를 타겟팅하거나, 테이블을 사전 세분화하여, 또는 GROUP BY 절을 사용하여 결과를 사전 그룹화하여 쿼리 수준에서 필요한 다운샘플링을 수행합니다.

데모 대시보드는 4가지 그래프 모듈을 표시합니다. 사용자가 미국의 한 주를 선택하면 앱은 각 모듈당 하나씩, 서로 다른 4가지 쿼리를 BigQuery에 전달하여 총 7GB의 데이터를 처리합니다. 각 BigQuery 쿼리를 실행하는 데는 평균 1~3초가 걸립니다. 이 프로세스 중 앱은 대기 상태를 유지하고 BigQuery에서 결과가 반환되기까지 대기합니다. 대시보드의 전체 응답 시간을 최적화하기 위해 이러한 4개의 쿼리는 다음 코드와 같이 별도의 스레드에서 동시에 실행됩니다.

def fetch_data(state):
    """
    Fetch data from BigQuery for the given US state by running
    the queries for all dashboard modules in parallel.
    """
    t0 = time.time()
    # Collect fetch methods for all dashboard modules
    fetch_methods = {module.id: getattr(module, 'fetch_data') for module in modules}
    # Create a thread pool: one separate thread for each dashboard module
    with concurrent.futures.ThreadPoolExecutor(max_workers=len(fetch_methods)) as executor:
        # Prepare the thread tasks
        tasks = {}
        for key, fetch_method in fetch_methods.items():
            task = executor.submit(fetch_method, state)
            tasks[task] = key
        # Run the tasks and collect results as they arrive
        results = {}
        for task in concurrent.futures.as_completed(tasks):
            key = tasks[task]
            results[key] = task.result()
    # Return results once all tasks have been completed
    t1 = time.time()
    timer.text = '(Execution time: %s seconds)' % round(t1 - t0, 4)
    return results

BigQuery에서 모든 결과를 수신하면 Bokeh의 그래프 라이브러리에 데이터가 표시됩니다. 예를 들어 다음 코드는 시간 경과에 따른 대기 오염 수준의 변화를 그래프로 표시합니다.

def make_plot(self, dataframe):
    self.source = ColumnDataSource(data=dataframe)
    palette = all_palettes['Set2'][6]
    hover_tool = HoverTool(tooltips=[
        ("Value", "$y"),
        ("Year", "@year"),
    ])
    self.plot = figure(
        plot_width=600, plot_height=300, tools=[hover_tool],
        toolbar_location=None)
    columns = {
        'pm10': 'PM10 Mass (µg/m³)',
        'pm25_frm': 'PM2.5 FRM (µg/m³)',
        'pm25_nonfrm': 'PM2.5 non FRM (µg/m³)',
        'lead': 'Lead (¹/₁₀₀ µg/m³)',
    }
    for i, (code, label) in enumerate(columns.items()):
        self.plot.line(
            x='year', y=code, source=self.source, line_width=3,
            line_alpha=0.6, line_color=palette[i], legend=label)

    self.title = Paragraph(text=TITLE)
    return column(self.title, self.plot)

Bokeh 서비스 배포

앱의 수평적 확장성을 늘리기 위해 앱 백엔드의 모든 구성요소는 GKE를 통해 Docker 컨테이너로 배포됩니다. 이러한 구성요소를 GKE에 배포하는 단계는 다음과 같습니다.

  1. 우선 Cloud Shell에서 다음 명령어를 실행하여 임의의 수인 2개의 노드가 포함된 GKE 클러스터를 만듭니다.

    gcloud container clusters create dashboard-demo-cluster \
      --tags dashboard-demo-node \
      --num-nodes=2
    
  2. 이전에 생성한 프로젝트 ID와 서비스 계정 키를 안전하게 저장하는 GKE 비밀번호를 만듭니다.

    export PROJECT_ID=$(gcloud info --format='value(config.project)')
    
    kubectl create secret generic project-id \
      --from-literal project-id=$PROJECT_ID
    
    kubectl create secret generic service-account-key \
      --from-file service-account-key=service-account-key.json
    
  3. 고정 IP 주소를 만듭니다.

    gcloud compute addresses create dashboard-demo-static-ip --global
    
  4. IP 주소를 포함하는 도메인을 자동으로 동일한 IP 주소로 분해하는 무료 DNS 서비스인 nip.io를 사용하여 도메인을 정의합니다.

    export STATIC_IP=$(gcloud compute addresses describe \
      dashboard-demo-static-ip --global --format="value(address)")
    
    export DOMAIN="${STATIC_IP}.nip.io"
    
    echo "My domain: ${DOMAIN}"
    
  5. 도메인의 GKE 비밀번호를 만듭니다.

    kubectl create secret generic domain --from-literal domain=$DOMAIN
    
  6. 이제 다음 명령어를 실행하여 Bokeh 서비스를 배포할 수 있습니다.

    kubectl create -f kubernetes/bokeh.yaml
    

마지막 단계에서는 임의의 수(여기에서는 2개)의 pod를 배포합니다. 이때 각 pod는 데모 앱의 인스턴스를 별도로 실행합니다. 또한 앞서 env.valueFrom.secretKeyRef 항목을 통해 만든 GKE 비밀번호를 환경 변수로 노출하여 앱에서 이 정보를 검색하고 BigQuery에 액세스할 수 있도록 합니다.

자세한 내용은 bokeh.yaml을 참조하세요.

Memcached 서비스

특정 기간 동안 대시보드에 표시되는 데이터가 변경되지 않을 것으로 예상되는 경우 성능 및 비용 최적화를 고려해야 합니다. 이를 위해 BigQuery는 기본적으로 24시간 동안 중복 쿼리의 결과를 내부적으로 캐싱합니다. 이로 인해 응답 시간이 크게 단축되고 불필요한 비용이 청구되지 않습니다. 자세한 내용은 캐시된 쿼리 결과 사용을 참조하세요.

자주 사용되는 데이터를 대시보드 앱의 메모리에 로컬로 캐싱하여 이 캐싱 메커니즘을 더욱 향상시킬 수 있습니다. 이 접근 방법은 BigQuery를 루프에서 제거하고 불필요한 네트워크를 차단하여 캐싱한 데이터를 수집합니다. 이 튜토리얼은 Memcached를 사용하여 이러한 유형의 앱 수준 캐싱을 처리합니다. Memcached는 매우 빠르며, 이 튜토리얼의 경우 응답 시간을 몇 초에서 및 밀리초로 줄입니다.

Memcached의 특징 중 하나는 부하 분산 기능이 내장되어 있지 않다는 것입니다. 그 대신 여러 Memcached pod 간 부하 분산을 다음 다이어그램과 같이 각 Bokeh pod에 포함된 Memcached 클라이언트가 수행해야 합니다.

Memchached pod의 아키텍처

Memcached 클라이언트에서 Memcached pod를 검색하려면 Memcached 서비스는 GKE 구성 파일 내의 clusterIP: None 항목을 사용하여 헤드리스로 선언되어야 합니다(memcached.yaml 참조). 그러면 Memcached 클라이언트는 memcached.default.svc.cluster.local 도메인 이름에 대해 kube-dns를 쿼리하여 개별 pod의 IP 주소를 검색합니다.

Memcached 서비스 배포

Bokeh 서비스와 비슷하게 Memcached 서비스는 Docker 컨테이너를 사용하여 Kubernetes를 사용하는 GKE에 배포됩니다.

다음 명령을 실행하여 Memcached 포드와 헤드리스 서비스를 배포하세요.

kubectl create -f kubernetes/memcached.yaml

부하 분산기 추가

이 시점에서 대시보드 앱은 비공개 서비스에서 실행됩니다. 사용자가 대시보드에 액세스할 수 있도록 만들려면 HTTPS 부하 분산기를 도입하여 인터넷에 앱을 노출해야 합니다. 이 작업은 다음 단계에 따라 수행합니다.

  1. SSL 인증서 생성
  2. 부하 분산기 만들기
  3. 연결 시간 제한 연장

SSL 인증서 생성

실제 시나리오에서 대시보드에 표시되는 데이터는 민감한 데이터이거나 비공개 데이터일 수 있습니다. 인터넷을 통해 이 데이터를 사용자에게 보내기 전에 SSL을 사용하여 암호화해야 합니다. 첫 번째 단계는 SSL 인증서를 만드는 것입니다.

프로덕션 설정에서는 공식 인증 기관을 통해 인증서를 발급해야 합니다. 이 튜토리얼에서는 다음 명령어를 실행하여 자체 서명 인증서를 발급할 수 있습니다.

export STATIC_IP=$(gcloud compute addresses describe \
  dashboard-demo-static-ip --global --format="value(address)")

export DOMAIN="${STATIC_IP}.nip.io"

mkdir /tmp/dashboard-demo-ssl

cd /tmp/dashboard-demo-ssl

openssl genrsa -out ssl.key 2048

openssl req -new -key ssl.key -out ssl.csr -subj "/CN=${DOMAIN}"

openssl x509 -req -days 365 -in ssl.csr -signkey ssl.key -out ssl.crt

cd -

HTTPS 부하 분산기 만들기

HTTPS 부하 분산기는 여러 가지 리소스로 구성됩니다.

  • 전역 전달 규칙
  • 상태 확인
  • 백엔드 서비스
  • URL 지도
  • 대상 프록시

GitHub 소스 저장소에 포함된 모든 리소스를 동시에 만들려면 다음 명령을 실행하세요.

./create-lb.sh

다음 명령으로 반환되는 URL을 방문하여 대시보드가 실행 중인지 확인하세요.

echo https://${STATIC_IP}.nip.io/dashboard

브라우저가 502 코드 오류를 반환해도 부하 분산기는 계속 배포됩니다. 이 배포를 완료하는 데 몇 분 정도 걸릴 수 있습니다. 몇 초 정도 기다린 후 페이지를 새로고침하세요. 페이지가 작동하고 대시보드가 표시될 때까지 이를 시도하세요.

이 시점에서 HTTPS 부하 분산기는 암호화를 종료합니다. 시스템에서 송수신하는 트래픽은 HTTPS 및 보안 WebSocket을 사용하고, 시스템 내의 트래픽은 일반적인 HTTP 및 WebSocket을 사용하여 암호화되지 않은 상태로 유지됩니다. 대부분의 시나리오에서는 이 수준의 암호화로 충분합니다. 추가 보안이 필요한 경우 Google Cloud 프로젝트의 Virtual Private Cloud 네트워크에서 SSL 암호화를 시행할 수 있습니다. VPC 네트워크에서 SSL 암호화를 설정하는 작업은 이 튜토리얼에서 다루지 않습니다.

연결 시간 제한 연장

기본적으로 HTTPS 부하 분산기는 30초 이상 유지된 모든 연결을 종료합니다.

대시보드의 WebSocket 연결을 더 오랫동안 유지하려면 연결 시간 제한을 연장해야 합니다. 다음 gcloud 명령어는 시간 제한을 1일(86,400초)로 설정합니다.

gcloud compute backend-services update dashboard-demo-service \
    --global --timeout=86400

정적 애셋 백엔드

Bokeh 포드는 대시보드 렌더링에 필요한 모든 정적 자바스크립트 및 CSS 파일을 직접 제공할 수 있습니다. 하지만 이러한 포드가 작업을 처리하면 몇 가지 단점이 발생합니다.

  • Bokeh 포드에 불필요한 부하가 발생하므로 동적 데이터 그래프와 같은 다른 유형의 리소스를 처리할 수 있는 용량이 잠재적으로 줄어듭니다.
  • 클라이언트의 지리적인 위치에 상관없이 클라이언트가 동일한 원본 서버에서 애셋을 다운로드해야 합니다.

이러한 단점을 완화하려면 정적 애셋을 효율적으로 제공하는 별도의 전용 백엔드를 만드세요.

이 정적 애셋 백엔드는 2가지 주요 구성요소를 사용합니다.

  • Cloud Storage에서 호스팅되며 원본 자바스크립트 및 CSS 애셋을 보유하는 버킷
  • 대시보드 사용자에게 이러한 애셋을 전역적으로 배포하여 지연 시간을 줄이고 페이지 로드 시간을 단축하는 Cloud CDN

다음 다이어그램은 이러한 아키텍처를 보여줍니다.

정적 애셋 백엔드의 아키텍처

정적 애셋 백엔드 만들기

  1. 다음 명령어를 실행하여 Bokeh 컨테이너에서 정적 애셋을 추출하고 임시 디렉터리에 로컬로 저장합니다.

    gcloud auth configure-docker --quiet
    
    export DOCKER_IMAGE="gcr.io/cloud-solutions-images/dashboard-demo"
    
    export STATIC_PATH=$(docker run $DOCKER_IMAGE bokeh info --static)
    
    export TMP_PATH="/tmp/dashboard-demo-static"
    
    mkdir $TMP_PATH
    
    docker run $DOCKER_IMAGE tar Ccf $(dirname $STATIC_PATH) - \
        static | tar Cxf $TMP_PATH -
    
  2. Cloud SDK에 포함된 gsutil 명령어를 사용하여 버킷을 만들고 이 버킷에 모든 애셋을 업로드합니다.

    export BUCKET="${PROJECT_ID}-dashboard-demo"
    
    # Create the bucket
    gsutil mb gs://$BUCKET
    
    # Upload the assets to the bucket
    gsutil -m cp -z js,css -a public-read -r $TMP_PATH/static gs://$BUCKET
    

    -z 옵션은 파일 이름 확장자가 jscss인 파일에 gzip 인코딩을 적용하여 네트워크 대역폭과 Cloud Storage 공간을 줄이고, 스토리지 비용을 절감하고, 페이지 로드 시간을 단축합니다. -a 옵션은 업로드한 애셋에 모든 클라이언트가 공개적으로 액세스할 수 있도록 public-read 권한을 설정합니다.

  3. --enable-cdn 옵션을 사용하는 Cloud CDN 지원을 포함하는 백엔드 버킷을 만듭니다.

    gcloud compute backend-buckets create dashboard-demo-backend-bucket \
        --gcs-bucket-name=$BUCKET --enable-cdn
    
  4. /static/* 디렉터리 내의 애셋을 요청하는 모든 트래픽에 대해 HTTPS 부하 분산기에 백엔드 버킷을 연결합니다.

    gcloud compute url-maps add-path-matcher dashboard-demo-urlmap \
        --default-service dashboard-demo-service \
        --path-matcher-name bucket-matcher \
        --backend-bucket-path-rules="/static/*=dashboard-demo-backend-bucket"
    
  5. 이 구성 변경사항이 전파되는 데 몇 분 정도 걸릴 수 있습니다. 잠시 기다린 후 x-goog-* 매개변수를 포함하는 정적 애셋의 응답 헤더를 확인하여 Cloud CDN이 작동하는지 확인합니다.

    curl -Iks https://${DOMAIN}/static/js/bokeh.min.js | grep x-goog
    

인증

이전에 부하 분산기 수준에서 설정된 SSL 암호화로 전송을 보호하지만 앱에 대한 액세스를 제어하고 잠재적인 악용을 방지하기 위해 인증 레이어를 추가하는 것이 좋습니다. 한 가지 옵션은 IAP를 사용하는 것입니다.

첫 번째 단계는 OAuth 동의 화면을 설정하는 것입니다.

  1. OAuth 동의 화면을 설정합니다.

    동의 화면 구성

    1. 사용자 유형에서 외부를 선택한 다음 만들기를 클릭합니다.
    2. 애플리케이션 이름Dashboard demo를 입력합니다.
    3. 지원 이메일에서 공개 연락처로 표시할 이메일 주소를 선택합니다. 이 주소는 내 이메일 주소나 내가 소유한 Google 그룹이어야 합니다.
    4. 저장을 클릭합니다.
  2. 사용자 인증 정보에서 사용자 인증 정보 만들기 > OAuth 클라이언트 ID를 클릭합니다.

  3. 애플리케이션 유형에서 웹 애플리케이션을 선택한 다음 이름Dashboard demo를 입력합니다.

  4. 세부정보 입력을 마쳤으면 만들기를 클릭하고 OAuth 클라이언트 창에 표시된 클라이언트 ID클라이언트 보안 비밀번호를 기록해 둡니다.

  5. '대시보드 데모' 사용자 인증 정보를 클릭합니다.

  6. 승인된 리디렉션 URI에 다음 형식의 항목을 추가합니다. [CLIENT_ID]를 이전 단계에서 기록해 둔 클라이언트 IP 값으로 바꿉니다.

    https://iap.googleapis.com/v1/oauth/clientIds/[CLIENT_ID]:handleRedirect
    
  7. Cloud Shell에서 다음 명령어를 실행하여 IAP를 사용 설정합니다. [CLIENT_ID][CLIENT_SECRET] 값을 이전 단계에서 기록해 둔 값으로 바꿉니다.

    gcloud beta compute backend-services update dashboard-demo-service --global \
        --iap=enabled,oauth2-client-id=[CLIENT_ID],oauth2-client-secret=[CLIENT_SECRET]
    
  8. 마지막으로 앱에 액세스하도록 허용할 구성원을 추가합니다. [EMAIL] 값을 Google 계정 이메일 주소로 바꿉니다.

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --role roles/iap.httpsResourceAccessor \
        --member user:[EMAIL]
    

이 구성 변경사항이 전파되는 데 몇 분 정도 걸릴 수 있습니다. 이 작업이 완료되면 앱이 IAP에 의해 보호되고 위에서 제공한 이메일 주소를 보유한 사용자만 앱에 액세스할 수 있습니다. 위의 마지막 단계에서 동일한 프로세스를 사용하여 더 많은 사용자를 추가할 수 있습니다.

삭제

이 튜토리얼에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

프로젝트 삭제

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

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

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

    리소스 관리로 이동

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

개별 리소스 삭제

다음 명령을 실행하면 전체 프로세스를 삭제하는 대신 개별 리소스를 삭제할 수 있습니다.

export PROJECT_ID=$(gcloud info --format='value(config.project)')

# Delete the load balancer resources
gcloud compute forwarding-rules \
    delete dashboard-demo-gfr --global --quiet
gcloud compute target-https-proxies \
    delete dashboard-demo-https-proxy --quiet
gcloud compute ssl-certificates \
    delete dashboard-demo-ssl-cert --quiet
gcloud compute url-maps \
    delete dashboard-demo-urlmap --quiet
gcloud compute backend-services \
    delete dashboard-demo-service --global --quiet
gcloud compute health-checks delete \
    dashboard-demo-basic-check --quiet
gcloud compute firewall-rules delete \
    gke-dashboard-demo-lb7-fw --quiet

# Delete the Kubernetes Engine cluster
gcloud container clusters delete dashboard-demo-cluster --quiet

# Delete the service account
export SERVICE_ACCOUNT_NAME="dashboard-demo"
gcloud iam service-accounts delete \
    "${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" --quiet

# Delete the backend bucket
gcloud compute backend-buckets delete dashboard-demo-backend-bucket --quiet

# Delete the Cloud Storage bucket
export BUCKET="${PROJECT_ID}-dashboard-demo"
gsutil -m rm -r gs://$BUCKET

# Delete the static IP address
gcloud compute addresses delete dashboard-demo-static-ip --global --quiet

# Delete the local Docker image
docker rmi -f gcr.io/cloud-solutions-images/dashboard-demo

마지막으로 OAuth 클라이언트 ID를 삭제하세요.

  1. 사용자 인증 정보 페이지를 엽니다.

    사용자 인증 정보 열기

  2. '대시보드 데모' 항목을 클릭합니다.

  3. 삭제를 클릭하고 한 번 더 삭제를 클릭하여 확인합니다.

다음 단계

  • Google Cloud에 대한 참조 아키텍처, 다이어그램, 튜토리얼, 권장사항 살펴보기. Cloud 아키텍처 센터 살펴보기