Python으로 Cloud Workstations를 사용한 InnerLoop 개발

1. 개요

이 실습에서는 컨테이너화된 환경에서 Python 애플리케이션을 개발하는 소프트웨어 엔지니어의 개발 워크플로를 간소화하도록 설계된 기능을 시연합니다. 일반적인 컨테이너 개발에서는 사용자가 컨테이너와 컨테이너 빌드 프로세스에 대한 세부정보를 이해해야 합니다. 또한 개발자는 일반적으로 흐름을 중단하고 IDE에서 벗어나 원격 환경에서 애플리케이션을 테스트하고 디버그해야 합니다. 이 튜토리얼에서 언급한 도구와 기술을 사용하면 개발자는 IDE를 벗어나지 않고도 컨테이너화된 애플리케이션으로 효과적으로 작업할 수 있습니다.

학습할 내용

이 실습에서는 다음을 포함하여 GCP에서 컨테이너를 사용하여 개발하는 방법을 알아봅니다.

  • 새 Python 시작 애플리케이션 만들기
  • 개발 프로세스 살펴보기
  • 간단한 CRUD 휴식 서비스 개발
  • GKE에 배포
  • 오류 상태 디버깅
  • 중단점 / 로그 활용 중
  • 변경사항을 GKE에 다시 핫 배포

58a4cdd3ed7a123a.png

2. 설정 및 요구사항

자습형 환경 설정

  1. Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 프로젝트 이름은 이 프로젝트 참가자의 표시 이름입니다. 이는 Google API에서 사용하지 않는 문자열이며 언제든지 업데이트할 수 있습니다.
  • 프로젝트 ID는 모든 Google Cloud 프로젝트에서 고유하며, 변경할 수 없습니다(설정된 후에는 변경할 수 없음). Cloud 콘솔이 고유한 문자열을 자동으로 생성합니다. 보통은 그게 뭔지 상관하지 않습니다. 대부분의 Codelab에서는 프로젝트 ID (일반적으로 PROJECT_ID로 식별됨)를 참조해야 합니다. 생성된 ID가 마음에 들지 않으면 무작위로 다른 ID를 생성할 수 있습니다. 또는 직접 시도해 보고 사용 가능한지 확인할 수도 있습니다. 이 단계 이후에는 변경할 수 없으며 프로젝트 기간 동안 유지됩니다.
  • 참고로 세 번째 값은 일부 API에서 사용하는 프로젝트 번호입니다. 이 세 가지 값에 대한 자세한 내용은 문서를 참고하세요.
  1. 다음으로 Cloud 리소스/API를 사용하려면 Cloud 콘솔에서 결제를 사용 설정해야 합니다. 이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 튜토리얼이 끝난 후에 요금이 청구되지 않도록 리소스를 종료하려면 만든 리소스를 삭제하거나 전체 프로젝트를 삭제하면 됩니다. Google Cloud 새 사용자에게는 미화 $300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

Cloud Shell 편집기 시작

이 실습은 Google Cloud Shell 편집기에서 사용할 수 있도록 설계 및 테스트되었습니다. 편집기에 액세스하려면

  1. https://console.cloud.google.com에서 Google 프로젝트에 액세스합니다.
  2. 오른쪽 상단에서 Cloud Shell 편집기 아이콘을 클릭합니다.

8560cc8d45e8c112.png

  1. 창 하단에 새 창이 열립니다.
  2. 편집기 열기 버튼을 클릭합니다.

9e504cb98a6a8005.png

  1. 편집기가 오른쪽에 탐색기가 표시되고 중앙에 편집기가 열립니다.
  2. 화면 하단에서 터미널 창도 사용할 수 있습니다.
  3. 터미널이 열려 있지 않으면 `ctrl+` 키 조합을 사용하여 새 터미널 창을 엽니다.

환경 설정

Cloud Shell에서 프로젝트의 ID와 프로젝트 번호를 설정합니다. PROJECT_IDPROJECT_ID 변수로 저장합니다.

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
    --format='value(projectNumber)')

이 실습에서 사용하는 인프라를 프로비저닝합니다.

이 실습에서는 GKE에 코드를 배포하고 Spanner 데이터베이스에 저장된 데이터에 액세스합니다. 또한 Cloud 워크스테이션을 IDE로 사용하게 됩니다. 아래 설정 스크립트가 이 인프라를 준비합니다.

  1. 설정 스크립트를 다운로드하고 실행 파일로 만듭니다.
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/python/setup_with_cw.sh
chmod +x setup_with_cw.sh
  1. setup_with_cw.sh 파일을 열고 현재 CHANGEME로 설정된 비밀번호 값을 수정하세요.
  2. 설정 스크립트를 실행하여 이 실습에서 사용할 GKE 클러스터와 Spanner 데이터베이스를 설정합니다.
./setup_with_cw.sh &

Cloud Workstations 클러스터

  1. Cloud 콘솔에서 Cloud Workstations를 엽니다. 클러스터가 READY 상태가 될 때까지 기다립니다.

305e1a3d63ac7ff6.png

워크스테이션 구성 만들기

  1. Cloud Shell 세션이 연결 해제된 경우 '다시 연결'을 클릭합니다. gcloud cli 명령어를 실행하여 프로젝트 ID를 설정합니다. 명령어를 실행하기 전에 아래의 샘플 프로젝트 ID를 Qwiklabs 프로젝트 ID로 바꿉니다.
gcloud config set project qwiklabs-gcp-project-id
  1. 터미널에서 아래 스크립트를 다운로드하고 실행하여 Cloud Workstations 구성을 만듭니다.
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/python/workstation_config_setup.sh
chmod +x workstation_config_setup.sh
./workstation_config_setup.sh
  1. 구성 섹션에서 결과를 확인합니다. READY 상태로 전환되기까지 2분이 소요됩니다.

2e23c2e9983d1ccf.png

  1. 콘솔에서 Cloud Workstations를 열고 새 인스턴스를 만듭니다.

a53adeeac81a78c8.png

  1. 이름을 my-workstation(으)로 변경하고 기존 구성(codeoss-python)을 선택합니다.

f052cd47701ec774.png

  1. 워크스테이션 섹션에서 결과를 확인합니다.

워크스테이션 실행

  1. 워크스테이션을 시작하고 실행합니다. 워크스테이션을 시작하는 데 몇 분 정도 걸립니다.

682f8a307032cba3.png

  1. 주소 표시줄의 아이콘을 클릭하여 타사 쿠키를 허용합니다. 1b8923e2943f9bc4.png

fcf9405b6957b7d7.png

  1. '작동하지 않는 사이트인가요?'를 클릭합니다.

36a84c0e2e3b85b.png

  1. '쿠키 허용'을 클릭합니다.

2259694328628fba.png

  1. 워크스테이션이 실행되면 Code OSS IDE가 표시됩니다. '완료로 표시'를 클릭합니다. 워크스테이션 IDE의

94874fba9b74cc22.png

3. 새 Python 시작 애플리케이션 만들기

이 섹션에서는 새 Python 애플리케이션을 만듭니다.

  1. 새 터미널을 엽니다.

c31d48f2e4938c38.png

  1. 새 디렉터리를 만들어 작업공간으로 열기
mkdir music-service && cd music-service

code-oss-cloud-workstations -r --folder-uri="$PWD"

이 메시지가 표시되면 허용 버튼을 클릭하여 워크스테이션에 복사하여 붙여넣을 수 있도록 합니다.

58149777e5cc350a.png

  1. requirements.txt라는 파일을 만들고 이 파일에 다음 콘텐츠를 복사합니다.

789e8389170bd900.png

Flask
gunicorn
google-cloud-spanner
ptvsd==4.3.2
  1. app.py라는 파일을 만들고 이 파일에 다음 코드를 붙여넣습니다.
import os
from flask import Flask, request, jsonify
from google.cloud import spanner

app = Flask(__name__)

@app.route("/")
def hello_world():
    message="Hello, World!"
    return message

if __name__ == '__main__':
    server_port = os.environ.get('PORT', '8080')
    app.run(debug=False, port=server_port, host='0.0.0.0')

  1. Dockerfile라는 파일을 만들고 다음을 붙여넣습니다.
FROM python:3.8
ARG FLASK_DEBUG=0
ENV FLASK_DEBUG=$FLASK_DEBUG
ENV FLASK_APP=app.py
WORKDIR /app
COPY requirements.txt .
RUN pip install --trusted-host pypi.python.org -r requirements.txt
COPY . .
ENTRYPOINT ["python3", "-m", "flask", "run", "--port=8080", "--host=0.0.0.0"]

참고: FLASK_DEBUG=1을 사용하면 Python flask 앱의 코드 변경사항을 자동으로 새로고침할 수 있습니다. 이 Dockerfile을 사용하면 이 값을 빌드 인수로 전달할 수 있습니다.

매니페스트 생성

터미널에서 다음 명령어를 실행하여 기본 skaffold.yaml 및 deployment.yaml을 생성합니다.

  1. 다음 명령어를 사용하여 Skaffold 초기화
skaffold init --generate-manifests

메시지가 표시되면 화살표를 사용하여 커서를 이동하고 스페이스바를 사용하여 옵션을 선택합니다.

선택:

  • 포트에 대한 8080
  • y: 구성을 저장합니다.

Skaffold 구성 업데이트

  • 기본 애플리케이션 이름 변경
  • skaffold.yaml 열기
  • 현재 dockerfile-image(으)로 설정된 이미지 이름을 선택합니다.
  • 마우스 오른쪽 버튼을 클릭하고 '모든 어커런스 변경'을 선택합니다.
  • 새 이름을 python-app(으)로 입력합니다.
  • 빌드 섹션을 다음과 같이 추가로 수정합니다.
  • docker.buildArgs를 추가하여 FLASK_DEBUG=1 전달
  • IDE에서 실행 중인 컨테이너로 *.py 파일의 변경사항을 로드하도록 설정 동기화

수정 후 skaffold.yaml 파일의 빌드 섹션은 아래와 같습니다.

build:
 artifacts:
 - image: python-app
   docker:
     buildArgs:
       FLASK_DEBUG: "1"
     dockerfile: Dockerfile
   sync:
     infer:
     - '**/*.py'

Kubernetes 구성 파일 수정

  1. 기본 이름 변경
  • deployment.yaml 파일 열기
  • 현재 dockerfile-image(으)로 설정된 이미지 이름을 선택합니다.
  • 마우스 오른쪽 버튼을 클릭하고 '모든 어커런스 변경'을 선택합니다.
  • 새 이름을 python-app(으)로 입력합니다.

4. 개발 과정 살펴보기

비즈니스 로직이 추가되었으므로 이제 애플리케이션을 배포하고 테스트할 수 있습니다. 다음 섹션에서는 Cloud Code 플러그인을 사용하는 방법을 설명합니다. 무엇보다도 이 플러그인은 Skaffold와 통합되어 개발 프로세스를 간소화합니다. 다음 단계에서 GKE에 배포하면 Cloud Code 및 Skaffold에서 자동으로 컨테이너 이미지를 빌드하여 Container Registry로 푸시한 다음 your 애플리케이션을 GKE에 배포합니다. 이 작업은 개발자 흐름에서 세부정보를 추상화하는 이면에서 발생합니다.

Google Cloud에 로그인

  1. Cloud Code 아이콘을 클릭하고 'Google Cloud에 로그인'을 선택합니다.

1769afd39be372ff.png

  1. '로그인 진행'을 클릭합니다.

923bb1c8f63160f9.png

  1. 터미널에서 출력을 확인하고 링크를 엽니다.

517fdd579c34aa21.png

  1. Qwiklabs 학생 인증 정보로 로그인합니다.

db99b345f7a8e72c.png

  1. '허용'을 선택합니다.

a5376553c430ac84.png

  1. 인증 코드를 복사하고 워크스테이션 탭으로 돌아갑니다.

6719421277b92eac.png

  1. 인증 코드를 붙여넣고 Enter 키를 누릅니다.

e9847cfe3fa8a2ce.png

Kubernetes 클러스터 추가

  1. 클러스터 추가

62a3b97bdbb427e5.png

  1. Google Kubernetes Engine을 선택합니다.

9577de423568bbaa.png

  1. 프로젝트를 선택합니다.

c5202fcbeebcd41c.png

  1. 'python-cluster'를 선택합니다. 기본 설정입니다.

719c2fc0a7f9e84f.png

  1. 이제 클러스터가 Cloud Code 아래의 Kubernetes 클러스터 목록에 표시됩니다. 여기에서 클러스터를 탐색하고 탐색하세요.

7e5f50662d4eea3c.png

gcloud CLI를 사용하여 현재 프로젝트 ID 설정

  1. Qwiklabs 페이지에서 이 실습의 프로젝트 ID를 복사합니다.

fcff2d10007ec5bc.png

  1. 터미널에서 gcloud cli 명령어를 실행하여 프로젝트 ID를 설정합니다. 명령어를 실행하기 전에 샘플 프로젝트 ID를 교체하세요. 아래 명령어를 실행하기 전에 프로젝트 ID를 SUBSTITUTE으로 입력하세요.
gcloud config set project qwiklabs-gcp-project-id

Kubernetes에 배포

  1. Cloud Shell 편집기 하단의 창에서 Cloud Code 를 선택합니다.

d99a88992e15fea9.png

  1. 상단에 표시되는 패널에서 Kubernetes에서 실행을 선택합니다. 메시지가 표시되면 '예'를 선택하여 현재 Kubernetes 컨텍스트를 사용합니다.

bfd65e9df6d4a6cb.png

이 명령어는 소스 코드의 빌드를 시작한 후 테스트를 실행합니다. 빌드 및 테스트를 실행하는 데 몇 분 정도 걸립니다. 이러한 테스트에는 단위 테스트와 배포 환경에 설정된 규칙을 확인하는 유효성 검사 단계가 포함됩니다. 이 검증 단계는 이미 구성되어 있으며 개발 환경에서 작업하는 동안에도 배포 문제에 대한 경고를 받을 수 있습니다.

  1. 명령어를 처음 실행하면 현재 Kubernetes 컨텍스트를 원하는지 묻는 프롬프트가 화면 상단에 표시되면 '예'를 선택합니다. 현재 컨텍스트를 수락하고 사용합니다.
  2. 그러면 어떤 Container Registry를 사용할지 묻는 프롬프트가 표시됩니다. 입력된 기본값을 수락하려면 Enter 키를 누르세요.
  3. '출력'을 선택합니다. 탭을 눌러 진행 상황과 알림을 확인합니다. 드롭다운에서 'Kubernetes: Run/Debug(Kubernetes: 실행/디버그)'를 선택합니다.

9c87ccbf5d06f50a.png

  1. 'Kubernetes: Run/Debug - DETAILS(Kubernetes: 실행/디버그 - 세부정보)'를 선택합니다. 오른쪽에 있는 채널 드롭다운에서 클릭하여 컨테이너에서 라이브 스트리밍되는 추가 세부정보 및 로그를 볼 수 있습니다.

804abc8833ffd571.png

빌드와 테스트가 완료되면 출력 탭 로그의 'Kubernetes: 실행/디버그'에 URL http://localhost: 8080이 나열됩니다. 합니다.

  1. Cloud Code 터미널에서 출력의 첫 번째 URL (http://localhost:8080)에 마우스를 가져간 다음 표시되는 도움말에서 '웹 미리보기 열기'를 선택합니다.
  2. 새 브라우저 탭이 열리고 Hello, World! 메시지가 표시됩니다.

핫 리로드

  1. app.py 파일을 엽니다.
  2. 인사말 메시지를 Hello from Python(으)로 변경

Output 창의 Kubernetes: Run/Debug 뷰에서 감시자가 업데이트된 파일을 Kubernetes의 컨테이너와 동기화하는 것을 즉시 확인할 수 있습니다.

Update initiated
Build started for artifact python-app
Build completed for artifact python-app

Deploy started
Deploy completed

Status check started
Resource pod/python-app-6f646ffcbb-tn7qd status updated to In Progress
Resource deployment/python-app status updated to In Progress
Resource deployment/python-app status completed successfully
Status check succeeded
...
  1. Kubernetes: Run/Debug - Detailed 뷰로 전환하면 뷰가 파일 변경사항을 인식한 다음 앱을 빌드하고 다시 배포합니다.
files modified: [app.py]
Syncing 1 files for gcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Copying files:map[app.py:[/app/app.py]]togcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Watching for changes...
[python-app] * Detected change in '/app/app.py', reloading
[python-app] * Restarting with stat
[python-app] * Debugger is active!
[python-app] * Debugger PIN: 744-729-662
  1. 업데이트된 결과를 보려면 이전 결과가 표시된 브라우저 탭을 새로고침하세요.

디버깅

  1. 디버그 뷰로 이동하여 현재 스레드 647213126d7a4c7b.png를 중지합니다. 메시지가 표시되면 각 실행 후 정리하도록 선택할 수 있습니다.
  2. 70d6bd947d04d1e6.png
  3. 하단 메뉴에서 Cloud Code를 클릭하고 Debug on Kubernetes를 선택하여 debug 모드로 애플리케이션을 실행합니다.
  • Output 창의 Kubernetes Run/Debug - Detailed 뷰에서 skaffold가 이 애플리케이션을 디버그 모드로 배포합니다.
  1. 프로세스가 완료되면 디버거가 연결되고 출력 탭에 Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully.이 표시되고 URL http://localhost:8080이 나열됩니다.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
  1. 하단 상태 표시줄의 색상이 파란색에서 주황색으로 변경되어 디버그 모드임을 나타냅니다.
  2. Kubernetes Run/Debug 뷰에서 디버그 가능한 컨테이너가 시작되었음을 확인합니다.
**************URLs*****************
Forwarded URL from service python-app: http://localhost:8080
Debuggable container started pod/python-app-8bd64cf8b-cskfl:python-app (default)
Update succeeded
***********************************

중단점 활용

  1. app.py 파일을 엽니다.
  2. return message라는 문을 찾습니다.
  3. 줄 번호 왼쪽의 빈 공간을 클릭하여 해당 줄에 중단점을 추가합니다. 중단점이 설정되었음을 알리는 빨간색 표시기가 표시됨
  4. 처음 실행하면 컨테이너 내부에서 소스의 위치를 묻는 프롬프트가 표시됩니다. 이 값은 Dockerfile의 디렉터리와 관련이 있습니다.

기본값을 수락하려면 Enter 키를 누르세요.

fccc866f32b5ed86.png

애플리케이션을 빌드하고 배포하는 데 몇 분 정도 걸립니다.

  1. 브라우저를 새로고침하고 디버거가 중단점에서 프로세스를 중지하며 GKE에서 원격으로 실행 중인 애플리케이션의 변수와 상태를 조사할 수 있습니다.
  2. 변수 섹션을 클릭합니다.
  3. 로컬을 클릭하면 "message" 변수를 찾을 수 있습니다.
  4. 변수 이름 'message'를 더블클릭합니다. 팝업에서 값을 "Greetings from Python"와 같은 다른 값으로 변경합니다.
  5. 디버그 제어판에서 계속 버튼(607c33934f8d6b39.png)을 클릭합니다.
  6. 브라우저에서 응답을 검토합니다. 이제 방금 입력한 업데이트된 값이 표시됩니다.
  7. '디버그' 중지 중지 버튼 647213126d7a4c7b.png을 눌러 모드를 종료하고 중단점을 다시 클릭하여 중단점을 삭제합니다.

5. 간단한 CRUD REST 서비스 개발

이제 애플리케이션이 컨테이너화된 개발을 위해 완전히 구성되었으며 Cloud Code를 사용하여 기본 개발 워크플로를 살펴봤습니다. 다음 섹션에서는 Google Cloud의 관리형 데이터베이스에 연결하는 REST 서비스 엔드포인트를 추가하여 학습한 내용을 연습합니다.

나머지 서비스 코딩

아래 코드는 Spanner를 애플리케이션 지원 데이터베이스로 사용하는 간단한 저장 서비스를 만듭니다. 다음 코드를 애플리케이션에 복사하여 애플리케이션을 만듭니다.

  1. app.py를 다음 콘텐츠로 바꿔 기본 애플리케이션을 만듭니다.
import os
from flask import Flask, request, jsonify
from google.cloud import spanner


app = Flask(__name__)


instance_id = "music-catalog"

database_id = "musicians"

spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)


@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

@app.route('/singer', methods=['POST'])
def create():
    try:
        request_json = request.get_json()
        singer_id = request_json['singer_id']
        first_name = request_json['first_name']
        last_name = request_json['last_name']
        def insert_singers(transaction):
            row_ct = transaction.execute_update(
                f"INSERT Singers (SingerId, FirstName, LastName) VALUES" \
                f"({singer_id}, '{first_name}', '{last_name}')"
            )
            print("{} record(s) inserted.".format(row_ct))

        database.run_in_transaction(insert_singers)

        return {"Success": True}, 200
    except Exception as e:
        return e



@app.route('/singer', methods=['GET'])
def get_singer():

    try:
        singer_id = request.args.get('singer_id')
        def get_singer():
            first_name = ''
            last_name = ''
            with database.snapshot() as snapshot:
                results = snapshot.execute_sql(
                    f"SELECT SingerId, FirstName, LastName FROM Singers " \
                    f"where SingerId = {singer_id}",
                    )
                for row in results:
                    first_name = row[1]
                    last_name = row[2]
                return (first_name,last_name )
        first_name, last_name = get_singer()  
        return {"first_name": first_name, "last_name": last_name }, 200
    except Exception as e:
        return e


@app.route('/singer', methods=['PUT'])
def update_singer_first_name():
    try:
        singer_id = request.args.get('singer_id')
        request_json = request.get_json()
        first_name = request_json['first_name']
        
        def update_singer(transaction):
            row_ct = transaction.execute_update(
                f"UPDATE Singers SET FirstName = '{first_name}' WHERE SingerId = {singer_id}"
            )

            print("{} record(s) updated.".format(row_ct))

        database.run_in_transaction(update_singer)
        return {"Success": True}, 200
    except Exception as e:
        return e


@app.route('/singer', methods=['DELETE'])
def delete_singer():
    try:
        singer_id = request.args.get('singer')
    
        def delete_singer(transaction):
            row_ct = transaction.execute_update(
                f"DELETE FROM Singers WHERE SingerId = {singer_id}"
            )
            print("{} record(s) deleted.".format(row_ct))

        database.run_in_transaction(delete_singer)
        return {"Success": True}, 200
    except Exception as e:
        return e

port = int(os.environ.get('PORT', 8080))
if __name__ == '__main__':
    app.run(threaded=True, host='0.0.0.0', port=port)

데이터베이스 구성 추가

Spanner에 안전하게 연결하려면 워크로드 ID를 사용하도록 애플리케이션을 설정하세요. 이렇게 하면 애플리케이션이 자체 서비스 계정 역할을 하고 데이터베이스에 액세스할 때 개별 권한을 가질 수 있습니다.

  1. deployment.yaml를 업데이트합니다. 파일 끝에 다음 코드를 추가합니다 (아래 예에서 탭 들여쓰기를 유지해야 합니다).
      serviceAccountName: python-ksa
      nodeSelector:
        iam.gke.io/gke-metadata-server-enabled: "true" 

변경 후 사양 섹션은 다음과 같이 표시됩니다.

   spec:
     containers:
     - name: python-app
       image: python-app
     serviceAccountName: python-ksa
     nodeSelector:
       iam.gke.io/gke-metadata-server-enabled: "true"

애플리케이션 배포 및 검증

  1. Cloud Shell 편집기 하단의 창에서 Cloud Code를 선택한 후 화면 상단의 Debug on Kubernetes를 선택합니다.
  2. 빌드와 테스트가 완료되면 출력 탭에 Resource deployment/python-app status completed successfully이 표시되고 URL이 나열됩니다. 'Forwarded URL from service python-app: http://localhost:8080'
  3. 항목을 몇 개 추가합니다.

cloudshell 터미널에서 아래 명령어를 실행합니다.

curl -X POST http://localhost:8080/singer -H 'Content-Type: application/json' -d '{"first_name":"Cat","last_name":"Meow", "singer_id": 6}'
  1. 터미널에서 아래 명령어를 실행하여 GET을 테스트합니다.
curl -X GET http://localhost:8080/singer?singer_id=6
  1. 삭제 테스트: 이제 다음 명령어를 실행하여 항목을 삭제해 봅니다. 필요한 경우 item-id의 값을 변경합니다.
curl -X DELETE http://localhost:8080/singer?singer_id=6
    This throws an error message
500 Internal Server Error

문제 파악 및 해결

  1. 디버그 모드로 이동하여 문제를 찾습니다. 다음은 몇 가지 팁입니다.
  • DELETE에 문제가 있다는 것을 알고 있습니다. 원하는 결과를 반환하지 않기 때문입니다. 따라서 delete_singer 메서드의 app.py에 중단점을 설정합니다.
  • 단계별로 실행하고 각 단계에서 변수를 관찰하여 왼쪽 창의 로컬 변수 값을 관찰합니다.
  • singer_idrequest.args와 같은 특정 값을 관찰하려면 이러한 변수를 Watch 창에 추가하세요.
  1. singer_id에 할당된 값은 None입니다. 코드를 변경하여 문제를 해결합니다.

수정된 코드 스니펫은 다음과 같습니다.

@app.route('/delete-singer', methods=['DELETE', 'GET'])
def delete_singer():
    try:
        singer_id = request.args.get('singer_id')
  1. 애플리케이션이 다시 시작되면 삭제를 시도하여 다시 테스트합니다.
  2. 디버그 툴바의 빨간색 정사각형 647213126d7a4c7b.png을 클릭하여 디버깅 세션을 중지합니다.

6. 삭제

축하합니다. 이 실습에서는 새로운 Python 애플리케이션을 처음부터 만들고 컨테이너에서 효과적으로 작동하도록 구성했습니다. 그런 다음 기존 애플리케이션 스택에 있는 것과 동일한 개발자 흐름에 따라 애플리케이션을 원격 GKE 클러스터에 배포하고 디버깅했습니다.

실습을 완료한 후 정리하는 방법은 다음과 같습니다.

  1. 실습에서 사용된 파일 삭제
cd ~ && rm -rf ~/music-service
  1. 프로젝트를 삭제하여 모든 관련 인프라 및 리소스를 삭제하세요.