1. 소개
최종 업데이트: 2021년 3월 5일
애플리케이션의 관측 가능성
관측 가능성 및 OpenTelemetry
관측 가능성은 시스템의 속성을 설명하는 데 사용되는 용어입니다. 관측 가능성이 있는 시스템을 통해 팀이 시스템을 적극적으로 디버그할 수 있습니다. 이러한 맥락에서 관측 가능성의 세 가지 핵심 요소 로그, 측정항목, trace는 시스템에서 관측 가능성을 얻기 위한 기본 계측입니다.
OpenTelemetry는 관측 가능성에 필요한 원격 분석 데이터 (로그, 측정항목, trace)의 계측 및 내보내기를 가속화하는 사양 및 SDK 모음입니다. OpenTelemetry는 CNCF에 따른 개방형 표준 커뮤니티 주도 프로젝트입니다. 프로젝트와 생태계가 제공하는 라이브러리를 활용함으로써 개발자는 공급업체 중립적인 방식으로 여러 아키텍처에 대해 애플리케이션을 계측할 수 있습니다.
분산 트레이스
로그, 측정항목, trace 중에서 trace는 시스템 내 프로세스의 특정 부분의 지연 시간을 알려주는 원격 분석입니다. 특히 마이크로서비스 시대에는 분산 추적이 전체 분산 시스템에서 지연 시간 병목 현상을 찾아내는 강력한 동인입니다.
분산된 트레이스를 분석할 때는 trace 데이터 시각화를 통해 전체 시스템 지연 시간을 한눈에 파악할 수 있습니다. 분산 트레이스에서는 다중 스팬이 포함된 Trace의 형태로 시스템 진입점에 대한 단일 요청을 처리하는 호출 집합을 처리합니다.
스팬은 분산 시스템에서 수행되는 개별 작업 단위를 나타내며 시작 시간과 중지 시간을 기록합니다. 스팬은 종종 서로 계층적 관계를 갖습니다. 아래 그림에서 모든 작은 스팬은 큰 /messages 스팬의 하위 스팬이며 시스템을 통해 작업 경로를 보여주는 하나의 Trace로 조합됩니다.
Google Cloud Trace는 분산 trace 백엔드의 옵션 중 하나이며 Google Cloud의 다른 제품과 원활하게 통합됩니다.
빌드할 항목
이 Codelab에서는 'Shakesapp'이라는 서비스에서 트레이스 정보를 계측합니다. Google Kubernetes Engine에서 실행되는 Kubernetes 클러스터에서 실행되는 Shakesapp의 아키텍처는 다음과 같습니다.
- 클라이언트가 서버에 쿼리 문자열 전송
- 서버가 클라이언트에서 쿼리를 수락하고, Google Cloud Storage에서 텍스트 형식의 모든 Shakespare 작업을 가져오고, 쿼리가 포함된 줄을 검색하고, 클라이언트와 일치하는 줄의 번호를 반환합니다.
요청에서 trace 정보를 계측합니다.
학습할 내용
- Python 프로젝트에서 OpenTelemetry Trace 라이브러리를 시작하는 방법
- 라이브러리로 스팬을 만드는 방법
- 앱 구성요소 간 네트워크를 통해 스팬 컨텍스트를 전파하는 방법
- trace 데이터를 Google Cloud Trace로 전송하는 방법
- Google Cloud Trace에서 trace를 분석하는 방법
이 Codelab에서는 마이크로서비스를 계측하는 방법을 설명합니다. 이해를 돕기 위해 이 예에는 3개의 구성요소 (부하 생성기, 클라이언트, 서버)만 포함되어 있지만 이 Codelab에서 설명하는 동일한 프로세스를 더 복잡한 대규모 시스템에도 적용할 수 있습니다.
필요한 항목
- Python 3에 관한 지식
2. 설정 및 요구사항
자습형 환경 설정
아직 Google 계정(Gmail 또는 Google Apps)이 없으면 계정을 만들어야 합니다. Google Cloud Platform Console(console.cloud.google.com)에 로그인하고 새 프로젝트를 만듭니다.
프로젝트가 이미 있으면 Console 왼쪽 위에서 프로젝트 선택 풀다운 메뉴를 클릭합니다.
그리고 표시된 대화상자에서 '새 프로젝트' 버튼을 클릭하여 새 프로젝트를 만듭니다.
아직 프로젝트가 없으면 첫 번째 프로젝트를 만들기 위해 다음과 비슷한 대화상자가 표시됩니다.
이후의 프로젝트 만들기 대화상자에서 새 프로젝트의 세부정보를 입력할 수 있습니다.
모든 Google Cloud 프로젝트에서 고유한 이름인 프로젝트 ID를 기억하세요(위의 이름은 이미 사용되었으므로 사용할 수 없습니다). 이 이름은 나중에 Codelab에서 PROJECT_ID로 참조됩니다.
아직 사용 설정하지 않은 경우 Google Cloud 리소스를 사용하고 Cloud Trace API를 사용 설정하려면 Developers Console에서 결제를 사용 설정해야 합니다.
이 codelab을 실행하는 과정에는 많은 비용이 들지 않지만 더 많은 리소스를 사용하려고 하거나 실행 중일 경우 비용이 더 들 수 있습니다(이 문서 마지막의 '삭제' 섹션 참조). Google Cloud Trace, Google Kubernetes Engine, Google Artifacat Registry의 가격은 공식 문서에 나와 있습니다.
- Google Cloud Observability 가격 책정
- 가격 책정 | Kubernetes Engine 문서
- Artifact Registry 가격 책정 | Artifact Registry 문서
Google Cloud Platform 신규 사용자는 $300 상당의 무료 체험판을 사용할 수 있으므로, 이 Codelab을 완전히 무료로 사용할 수 있습니다.
Google Cloud Shell 설정
Google Cloud 및 Google Cloud Trace는 노트북에서 원격으로 조작할 수 있지만, 이 Codelab에서는 Cloud에서 실행되는 명령줄 환경인 Google Cloud Shell을 사용합니다.
이 Debian 기반 가상 머신에는 필요한 모든 개발 도구가 로드되어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 즉, 이 Codelab에 필요한 것은 브라우저뿐입니다(Chromebook에서도 작동 가능).
Cloud 콘솔에서 Cloud Shell을 활성화하려면 Cloud Shell 활성화 를 클릭하세요. 환경을 프로비저닝하고 연결하는 데 몇 분 정도 걸립니다.
Cloud Shell에 연결되면 사용자 인증이 이미 완료되었고 프로젝트가 내 PROJECT_ID
에 설정되어 있음을 확인할 수 있습니다.
gcloud auth list
명령어 결과
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
명령어 결과
[core] project = <PROJECT_ID>
어떤 이유로든 프로젝트가 설정되지 않았으면 다음 명령어를 실행하면 됩니다.
gcloud config set project <PROJECT_ID>
PROJECT_ID
를 찾고 계신가요? 설정 단계에서 사용한 ID를 확인하거나 Cloud Console 대시보드에서 확인하세요.
또한 Cloud Shell은 기본적으로 이후 명령어를 실행할 때 유용할 수 있는 몇 가지 환경 변수를 설정합니다.
echo $GOOGLE_CLOUD_PROJECT
명령어 출력
<PROJECT_ID>
마지막으로 기본 영역 및 프로젝트 구성을 설정합니다.
gcloud config set compute/zone us-central1-f
다양한 영역을 선택할 수 있습니다. 자세한 내용은 리전 및 영역을 참조하세요.
Python 설정
이 Codelab에서는 '시'를 사용합니다. 패키지 버전을 엄격하게 관리해야 합니다 Cloud Shell에서 다음 명령어를 실행합니다.
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 - source $HOME/.poetry/env
Google Kubernetes 클러스터 설정
이 Codelab에서는 Google Kubernetes Engine (GKE)에서 마이크로서비스 클러스터를 실행합니다. 이 Codelab의 프로세스는 다음과 같습니다.
- Cloud Shell에 기준 프로젝트 다운로드
- 마이크로서비스를 컨테이너에 빌드
- Google Artifact Registry (GAR)에 컨테이너 업로드
- GKE에 컨테이너 배포
- trace 계측을 위한 서비스의 소스 코드 수정
- 2단계로 이동
Kubernetes Engine 사용 설정
먼저 GKE에서 Shakesapp이 실행되는 Kubernetes 클러스터를 설정했으므로 GKE를 사용 설정해야 합니다. 'Kubernetes Engine' 메뉴로 이동합니다. 사용 설정 버튼을 누릅니다.
이제 Kubernetes 클러스터를 만들 준비가 되었습니다.
Kubernetes 클러스터 만들기
Cloud Shell에서 다음 명령어를 실행하여 Kubernetes 클러스터를 만듭니다. Artifact Registry 저장소를 만드는 데 사용한 리전에 영역 값이 있는지 확인하세요. 저장소 리전에 영역이 포함되지 않으면 영역 값을 us-central1-f
로 변경합니다.
gcloud container clusters create otel-trace-codelab --zone us-central1-f \ --num-nodes 1 \ --machine-type e2-highcpu-4
명령어 결과
Creating cluster otel-trace-codelab in us-central1-f... Cluster is being health-checked (master is healthy)...done. Created [https://container.googleapis.com/v1/projects/psychic-order-307806/zones/us-central1-f/clusters/otel-trace-codelab]. To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab?project=psychic-order-307806 kubeconfig entry generated for otel-trace-codelab. NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS otel-trace-codelab us-central1-f 1.18.12-gke.1210 104.154.162.176 e2-medium 1.18.12-gke.1210 3 RUNNING
Artifact Registry 및 Skaffold 설정
이제 배포할 Kubernetes 클러스터가 준비되었습니다. 다음으로 컨테이너를 푸시하고 배포하기 위한 Container Registry를 준비합니다. 이 단계에서는 GAR과 Scaffold를 설정해야 합니다.
Artifact Registry 설정
'Artifact Registry' 메뉴로 이동합니다. 활성화 버튼을 누릅니다.
잠시 후 GAR의 저장소 브라우저가 표시됩니다. '저장소 만들기'를 클릭합니다. 버튼을 클릭하고 저장소 이름을 입력합니다.
이 Codelab에서는 새 저장소의 이름을 trace-codelab
로 지정합니다. 아티팩트 형식은 'Docker'입니다. 위치 유형은 '지역'입니다 Google Compute Engine 기본 영역에 설정한 리전과 가까운 리전을 선택합니다. 예를 들어 이 예시에서는 'us-central1-f'를 선택했습니다. 여기서는 'us-central1 (아이오와)'을 선택합니다. 그런 다음 '만들기'를 클릭합니다. 버튼을 클릭합니다.
이제 'trace-codelab'이 표시됩니다. 확인할 수 있습니다
나중에 여기로 다시 돌아와 레지스트리 경로를 확인합니다.
Skaffold 설정
Skaffold는 Kubernetes에서 마이크로서비스 실행을 빌드할 때 유용한 도구입니다. 작은 명령어 집합으로 애플리케이션의 컨테이너를 빌드, 푸시, 배포하는 워크플로를 처리합니다. Skaffold는 기본적으로 Docker Registry를 Container Registry로 사용하므로 컨테이너를 푸시할 때 GAR을 인식하도록 Skaffold를 구성해야 합니다.
Cloud Shell을 다시 열고 Skaffold가 설치되어 있는지 확인합니다. Cloud Shell은 기본적으로 Skaffold를 환경에 설치합니다. 다음 명령어를 실행하고 Skaffold 버전을 확인합니다.
skaffold version
명령어 결과
v1.20.0
이제 skaffold가 사용할 기본 저장소를 등록할 수 있습니다. 레지스트리 경로를 가져오려면 Artifact Registry 대시보드로 이동하여 이전 단계에서 방금 설정한 저장소의 이름을 클릭합니다.
그러면 페이지 상단에 탐색경로 트레일이 표시됩니다. 아이콘을 클릭하여 레지스트리 경로를 클립보드에 복사합니다.
복사 버튼을 클릭하면 브라우저 하단에 다음과 같은 메시지가 있는 대화상자가 표시됩니다.
"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" 이(가) 복사되었습니다.
Cloud Shell로 돌아갑니다. 대시보드에서 방금 복사한 값을 사용하여 skaffold config set default-repo
명령어를 실행합니다.
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
명령어 결과
set value default-repo to us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab for context gke_stackdriver-sandbox-3438851889_us-central1-b_stackdriver-sandbox
또한 레지스트리를 Docker 구성으로 구성해야 합니다. 다음 명령어를 실행합니다.
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
명령어 결과
{ "credHelpers": { "gcr.io": "gcloud", "us.gcr.io": "gcloud", "eu.gcr.io": "gcloud", "asia.gcr.io": "gcloud", "staging-k8s.gcr.io": "gcloud", "marketplace.gcr.io": "gcloud", "us-central1-docker.pkg.dev": "gcloud" } } Adding credentials for: us-central1-docker.pkg.dev
이제 GKE에서 Kubernetes 컨테이너를 설정하는 다음 단계로 진행할 차례입니다.
요약
이 단계에서는 Codelab 환경을 설정합니다.
- Cloud Shell 설정
- Container Registry용 Artifact Registy 저장소 생성됨
- Container Registry를 사용하도록 Skaffold 설정
- Codelab 마이크로서비스가 실행되는 Kubernetes 클러스터를 만들었습니다.
다음 단계
다음 단계에서는 마이크로서비스를 빌드하여 클러스터에 푸시하고 배포합니다.
3. 마이크로서비스 빌드, 푸시, 배포
Codelab 자료 다운로드
이전 단계에서는 이 Codelab의 모든 기본 요건을 설정했습니다. 이제 이를 기반으로 전체 마이크로서비스를 실행할 준비가 되었습니다. 이 Codelab 자료는 GitHub에서 호스팅되므로 다음 git 명령어를 사용하여 Cloud Shell 환경에 다운로드합니다.
cd ~ git clone https://github.com/GoogleCloudPlatform/opentelemetry-trace-codelab-python.git
프로젝트의 디렉터리 구조는 다음과 같습니다.
shakesapp-python ├── LICENSE ├── manifests │ ├── client.yaml │ ├── loadgen.yaml │ └── server.yaml ├── proto │ └── shakesapp.proto ├── skaffold.yaml └── src ├── client ├── loadgen └── server
- 매니페스트: Kubernetes 매니페스트 파일
- proto: 클라이언트와 서버 간 통신을 위한 proto 정의
- src: 각 서비스의 소스 코드 디렉터리
- skaffold.yaml: skaffold용 구성 파일
Skaffold 명령어 실행
마지막으로, 방금 만든 Kubernetes 클러스터에 전체 콘텐츠를 빌드, 푸시, 배포할 준비가 되었습니다. 여러 단계가 포함된 것처럼 들리지만 실제로는 Scaffold가 모든 것을 처리합니다. 다음 명령어로 시도해 보겠습니다.
cd shakesapp-python skaffold run --tail
명령어를 실행하는 즉시 docker build
의 로그 출력이 표시되고 레지스트리에 성공적으로 푸시되었는지 확인할 수 있습니다.
명령어 결과
... ---> Running in c39b3ea8692b ---> 90932a583ab6 Successfully built 90932a583ab6 Successfully tagged us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step1 The push refers to repository [us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice] cc8f5a05df4a: Preparing 5bf719419ee2: Preparing 2901929ad341: Preparing 88d9943798ba: Preparing b0fdf826a39a: Preparing 3c9c1e0b1647: Preparing f3427ce9393d: Preparing 14a1ca976738: Preparing f3427ce9393d: Waiting 14a1ca976738: Waiting 3c9c1e0b1647: Waiting b0fdf826a39a: Layer already exists 88d9943798ba: Layer already exists f3427ce9393d: Layer already exists 3c9c1e0b1647: Layer already exists 14a1ca976738: Layer already exists 2901929ad341: Pushed 5bf719419ee2: Pushed cc8f5a05df4a: Pushed step1: digest: sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe size: 2001
모든 서비스 컨테이너를 푸시하면 Kubernetes 배포가 자동으로 시작됩니다.
명령어 결과
sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 size: 1997 Tags used in deployment: - serverservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step4@sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe - clientservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/clientservice:step4@sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 - loadgen -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/loadgen:step4@sha256:eea2e5bc8463ecf886f958a86906cab896e9e2e380a0eb143deaeaca40f7888a Starting deploy... - deployment.apps/clientservice created - service/clientservice created - deployment.apps/loadgen created - deployment.apps/serverservice created - service/serverservice created
주의: '지정된 이미지 저장소에 대한 푸시 액세스 권한 없음'과 같은 오류가 발생하면 skaffold의 기본 저장소에 있는 구성에 관계없이 skaffold 명령어가 Docker Hub (docker.io)로 이미지를 푸시하려고 하는지 확인하세요. 이 경우 '–default-repo'를 추가해 보세요. 'Scaffold 실행' 옵션 추가할 수 있습니다.
$ skaffold 실행 –tail –default-repo=us-central1-docker.pkg.dev/[project ID]/[repository name]
배포 후에는 다음과 같이 각 컨테이너의 stdout에 내보낸 실제 애플리케이션 로그가 표시됩니다.
명령어 결과
[server] {"event": "starting server: 0.0.0.0:5050", "severity": "info", "timestamp": "2021-03-17T05:25:56.758575Z"} [client] [2021-03-17 05:25:54 +0000] [1] [INFO] Starting gunicorn 20.0.4 [client] [2021-03-17 05:25:54 +0000] [1] [INFO] Listening at: http://0.0.0.0:8080 (1) [client] [2021-03-17 05:25:54 +0000] [1] [INFO] Using worker: threads [client] [2021-03-17 05:25:54 +0000] [7] [INFO] Booting worker with pid: 7 [client] {"event": "server address is serverservice:5050", "severity": "info", "timestamp": "2021-03-17T05:25:54.888627Z"} [client] {"event": "request to server with query: world", "severity": "info", "timestamp": "2021-03-17T05:26:11.550923Z"} [server] {"event": "query: world", "severity": "info", "timestamp": "2021-03-17T05:26:11.567048Z"} [loadgen] {"event": "check connectivity: http://clientservice:8080/_healthz", "severity": "info", "timestamp": "2021-03-17T05:26:11.533605Z"} [loadgen] {"event": "/_healthz response: ok", "severity": "info", "timestamp": "2021-03-17T05:26:11.544267Z"} [loadgen] {"event": "confirmed connection ot clientservice", "severity": "info", "timestamp": "2021-03-17T05:26:11.544527Z"}
마지막으로 서비스의 분산 추적을 위해 OpenTelemetry로 애플리케이션을 계측할 준비가 되었습니다.
요약
이 단계에서는 개발자 환경에 Codelab 자료를 준비했으며 Scaffold가 예상대로 실행되는지 확인했습니다.
다음 단계
다음 단계에서는 loadgen 서비스의 소스 코드를 수정하여 trace 정보를 계측합니다.
4. HTTP 계측
trace 계측 및 전파 개념
소스 코드를 수정하기 전에 간단한 다이어그램으로 분산 trace의 작동 방식을 간략하게 설명하겠습니다.
이 예시에서는 코드를 계측하여 Trace 및 스팬 정보를 Cloud Trace로 내보내고, loadgen 서비스에서 서버 서비스로의 요청에서 trace 컨텍스트를 전파합니다.
Cloud Trace가 Trace ID 및 스팬 ID와 같은 Trace 메타데이터를 전송해야 합니다. 이렇게 하면 Trace ID가 동일한 모든 스팬을 trace 하나로 조합할 수 있습니다. 또한 애플리케이션은 다운스트림 서비스를 요청할 때 trace 컨텍스트 (트레이스 ID와 상위 스팬의 스팬 ID의 조합)를 전파하여 처리 중인 trace 컨텍스트를 알 수 있어야 합니다.
OpenTelemetry는 다음과 같은 이점이 있습니다.
- 고유 Trace ID 및 스팬 ID 생성
- Trace ID 및 스팬 ID를 백엔드로 내보내기
- trace 컨텍스트를 다른 서비스에 전파하기 위해
계측 첫 번째 스팬
계측 부하 생성기 서비스
Cloud Shell 오른쪽 상단에 있는 버튼을 눌러 Cloud Shell 편집기를 엽니다. 왼쪽 창의 탐색기에서 src/loadgen/loadgen.py
를 열고 main
함수를 찾습니다.
src/loadgen/loadgen.py
def main():
...
# start request loop to client service
logger.info("start client request loop")
addr = f"http://{target}"
while True:
logger.info("start request to client")
call_client(addr)
logger.info("end request to client")
time.sleep(2.0)
main
함수에서 call_client
함수를 호출하는 루프를 볼 수 있습니다. 현재 구현에서 sectoin에는 함수 호출의 시작과 끝을 기록하는 로그 행이 2개 있습니다. 이제 스팬 정보를 계측하여 함수 호출의 지연 시간을 추적해 보겠습니다.
먼저 고유한 Trace ID와 스팬 ID로 스팬을 만들어야 합니다. OpenTelemetry는 이와 관련된 편리한 라이브러리를 제공합니다. 다음 줄을 추가하여 OpenTelemetry 라이브러리를 코드에 가져옵니다.
import structlog
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.instrumentation.requests import RequestsInstrumentor
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
부하 생성기가 requests
모듈을 통해 HTTP에서 클라이언트 애플리케이션을 호출하므로 requests
용 확장 프로그램 패키지를 사용하고 계측을 사용 설정합니다.
from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
+
+RequestsInstrumentor().instrument()
그런 다음 Trace Contenxt 및 내보내기 설정을 처리하는 Tracer 인스턴스를 설정합니다.
target = os.environ.get("CLIENT_ADDR", "0.0.0.0:8080")
+ exporter = CloudTraceSpanExporter()
+ trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(exporter))
+ tracer = trace.get_tracer(__name__)
+ propagate.set_global_textmap(CloudTraceFormatPropagator())
+ trace.set_tracer_provider(TracerProvider())
+
# connectivity check to client service
healthz = f"http://{target}/_healthz"
logger.info(f"check connectivity: {healthz}")
이 Codelab은 트레이스 계측 작동 방식을 이해하기 위한 Codelab이므로 모든 요청을 기록하고 백엔드로 전송하도록 Tracer를 구성합니다. (SimpleSpanProcessor()
) 이는 프로덕션 환경에 적합하지 않으므로 프로덕션 애플리케이션을 계측할 때 이 부분을 변경해야 합니다.
이제 트레이서로 스팬을 계측할 수 있습니다. 여기서 요점은 스팬을 명시적으로 생성해야 한다는 것입니다. 그게 전부입니다. 스팬에 이벤트 메타데이터를 추가하는 줄이 두 개 있지만 고유한 Trace ID 및 스팬 ID를 수동으로 생성하여 스팬에 삽입할 필요는 없습니다.
logger.info("start client request loop")
addr = f"http://{target}"
while True:
- logger.info("start request to client")
- call_client(addr)
- logger.info("end request to client")
+ with tracer.start_as_current_span("loadgen") as root_span:
+ root_span.add_event(name="request_start")
+ logger.info("start request to client")
+ call_client(addr)
+ root_span.add_event(name="request_end")
+ logger.info("end request to client")
time.sleep(2.0)
Docker 빌드가 필요한 OpenTelemetry 패키지를 가져오려면 다음 명령어를 실행합니다.
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-requests=^0.20b0"
상응하는 종속 항목 설명이 pyproject.toml
로 작성되었는지 확인할 수 있습니다.
계측 클라이언트 서비스
이전 섹션에서는 아래 그림에서 빨간색 직사각형으로 둘러싸인 부분을 계측했습니다. 부하 생성기 서비스에서 스팬 정보를 계측했습니다. 부하 생성기 서비스와 마찬가지로 이제 클라이언트 서비스를 계측해야 합니다. 부하 생성기 서비스와의 차이점은 클라이언트 서비스는 HTTP 헤더의 부하 생성기 서비스에서 전파된 Trace ID 정보를 추출하고 ID를 사용하여 스팬을 생성해야 한다는 것입니다.
Cloud Shell 편집기를 열고 부하 생성기 서비스에서 했던 것처럼 필수 모듈을 추가합니다.
src/client/client.py
import flask
import grpc
import structlog
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.instrumentation.flask import FlaskInstrumentor
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import \
+ CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
사용자 대신 Flask 애플리케이션의 자동 계측을 통해 HTTP 헤더를 추출하여 한 줄의 코드로 Trace Context를 가져올 수 있는 FlaskInstrumentor
를 가져왔습니다. OpenTelemetry 커뮤니티는 다른 주요 라이브러리와 유사하게 유용한 통합을 제공합니다. 자세한 내용은 공식 문서를 참고하세요.
app = flask.Flask(__name__)
+FlaskInstrumentor().instrument_app(app)
계측을 시작하기 전에 마찬가지로 부하 생성기 서비스에서 했던 것과 비슷하게 Tracer 인스턴스를 준비해야 합니다.
logger.info(f"server address is {SERVER_ADDR}")
+exporter = CloudTraceSpanExporter()
+trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(exporter))
+propagate.set_global_textmap(CloudTraceFormatPropagator())
+trace.set_tracer_provider(TracerProvider())
@app.route("/")
def main_handler():
....
이제 핸들러에 계측을 추가할 준비가 되었습니다. main_handler()
을 찾아 서버 서비스에 gRPC 요청을 발생시키는 부분을 수정합니다.
@app.route("/")
def main_handler():
q, count = random.choice(list(queries.items()))
# get Tracer
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("client") as cur_span:
channel = grpc.insecure_channel(SERVER_ADDR)
stub = shakesapp_pb2_grpc.ShakespeareServiceStub(channel)
logger.info(f"request to server with query: {q}")
cur_span.add_event("server_call_start")
resp = stub.GetMatchCount(shakesapp_pb2.ShakespeareRequest(query=q))
cur_span.add_event("server_call_end")
if count != resp.match_count:
raise UnexpectedResultError(
f"The expected count for '{q}' was {count}, but result was {resp.match_count } obtained"
)
result = str(resp.match_count)
logger.info(f"matched count for '{q}' is {result}")
return result
부하 생성기 서비스와 마찬가지로 다음 명령어로 pyproject.toml
에 필수 패키지를 추가합니다.
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-flask=^0.20b0"
그런 다음 skaffold run
명령어로 애플리케이션을 실행하고 Cloud Trace 대시보드에 표시되는 내용을 확인합니다.
skaffold run --tail
빌드, 푸시, 배포 메시지를 확인한 후 JSON 형식의 애플리케이션 로그를 볼 수 있습니다. Cloud Trace로 이동 > trace 정보를 얻었는지 확인하는 trace 목록 부하 생성기 서비스가 클라이언트 서비스에 주기적으로 요청을 전송하고 모든 요청에 대해 trace를 사용 설정했기 때문에 trace 목록에 많은 점이 표시되기 시작합니다.
이 중 하나를 클릭하면 요청 및 응답 프로세스 중 각 부분의 지연 시간을 설명하는 다음과 같은 폭포식 구조 그래프가 표시됩니다. '이벤트 표시' 옆의 체크박스를 찾으면 폭포식 구조 그래프 내에 주석을 볼 수 있습니다. 이러한 주석은 코드에서 span.add_event()
메서드로 계측한 주석입니다.
서버 서비스의 스팬이 표시되지 않을 수도 있습니다. 정답입니다. 서버 서비스에서 스팬을 전혀 계측하지 않았기 때문입니다.
요약
이 단계에서는 부하 생성기 서비스와 클라이언트 서비스를 계측하고 서비스 간에 Trace Context를 성공적으로 전파하고 두 서비스의 스팬 정보를 Cloud Trace로 내보낼 수 있음을 확인했습니다.
다음 단계
다음 단계에서는 클라이언트 서비스와 서버 서비스를 계측하여 gRPC를 통해 Trace Context를 전파하는 방법을 확인합니다.
5. gRPC 계측
이전 단계에서는 이 마이크로서비스에서 요청의 전반부를 계측했습니다. 이 단계에서는 클라이언트 서비스와 서버 서비스 간의 gRPC 통신을 계측합니다. (아래 그림에서 녹색과 보라색 직사각형)
gRPC 클라이언트의 자동 계측
OpenTelemetry의 생태계는 개발자가 애플리케이션을 계측하는 데 도움이 되는 편리한 라이브러리를 다양하게 제공합니다. 이전 단계에서는 '요청'에 자동 계측을 사용했습니다. 모듈을 마칩니다 이 단계에서는 gRPC를 통해 Trace Context를 전파하려고 하므로 라이브러리를 사용합니다.
src/client/client.py
import flask
import grpc
import structlog
from opentelemetry import propagate, trace
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
+from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.propagators.cloud_trace_propagator import \
CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
app = flask.Flask(__name__)
FlaskInstrumentor().instrument_app(app)
+GrpcInstrumentorClient().instrument()
클라이언트 서비스의 경우 계측을 위해 해야 하는 작업이 매우 작습니다. 우리가 해야 할 일은 Trace ID와 gRPC를 통해 현재 스팬의 스팬 ID의 조합인 Trace Context를 전파하는 것입니다. 따라서 Hander 함수의 gRPC 클라이언트가 Trace 컨텍스트를 HTTP 헤더 아래에 삽입할 수 있도록 GrpcInstrumentatorClient.instrument()
를 호출합니다.
poetry add
명령어로 pyproject.toml
에 새 종속 항목을 추가해야 합니다.
poetry add "opentelemetry-instrumentation-grpc=^0.20b0"
gRPC 서버의 자동 계측
gRPC 클라이언트에서와 마찬가지로 gRPC 서버의 자동 계측을 호출합니다. 다음과 같은 가져오기를 추가하고 파일 상단에서 GrpcInstrumentationServer().instrument()
를 호출합니다.
주의: HX 에이전트가 끝날 때까지
GrpcInstrumentationServe()
이 단계에서는
GrpcInstrumentationClient()
.
src/server/server.py
import grpc
import structlog
from google.cloud import storage
from grpc_health.v1 import health_pb2, health_pb2_grpc
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.instrumentation.grpc import GrpcInstrumentorServer
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
BUCKET_NAME = "dataflow-samples"
BUCKET_PREFIX = "shakespeare/"
+# enable auto gRPC server trace instrumentation
+GrpcInstrumentorServer().instrument()
+
그런 다음 내보내기를 추가하여 Cloud Trace 백엔드로 trace 정보를 전송해 보겠습니다. serve()
함수에 다음 코드를 추가합니다.
def serve():
+ # start trace exporter
+ trace.set_tracer_provider(TracerProvider())
+ trace.get_tracer_provider().add_span_processor(
+ SimpleSpanProcessor(CloudTraceSpanExporter())
+ )
+ propagators.set_global_textmap(CloudTraceFormatPropagator())
+
+ # add gRPC services to server
server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
service = ShakesappService()
shakesapp_pb2_grpc.add_ShakespeareServiceServicer_to_server(service, server)
health_pb2_grpc.add_HealthServicer_to_server(service, server)
서버 서비스에 새로 추가된 패키지를 추가해야 합니다.
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-instrumentation-grpc=^0.20b0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation=^0.20b0"
마이크로서비스 실행 및 트레이스 확인
그런 다음 skaffold 명령어를 사용하여 수정된 코드를 실행합니다.
skaffold run --tail
이제 Cloud Trace의 Trace 목록 페이지에 여러 trace가 표시됩니다. trace 중 하나를 클릭하면 부하 생성기 서비스에서 서버 서비스까지의 요청 전반에 걸쳐 스팬이 있음을 알 수 있습니다.
요약
이 단계에서는 OpenTelemetry 생태계 라이브러리의 지원을 통해 gRPC 기반 통신을 계측했습니다. 또한 부하 생성기 서비스에서 생성된 Trace Context가 서버 서비스에 성공적으로 전달되었음을 확인했습니다.
6. 축하합니다
OpenTelemery로 분산 트레이스를 성공적으로 만들고 Google Cloud Trace에서 마이크로서비스 전반의 요청 지연 시간을 확인했습니다.
더 많은 연습을 하려면 다음 주제를 직접 시도해 보세요.
- 현재 구현은 상태 점검에서 생성된 모든 스팬을 전송합니다. Cloud Trace에서 이러한 스팬을 필터링하려면 어떻게 해야 하나요? 힌트는 여기에서 확인하세요.
- 이벤트 로그를 스팬과 연결하여 Google Cloud Trace 및 Google Cloud Logging에서 어떻게 작동하는지 확인합니다. 힌트는 여기에서 확인하세요.
- 일부 서비스를 다른 언어의 서비스로 바꾸고 해당 언어의 OpenTelemetry로 계측해 보세요.
주의: Google Kubernetes Engine 및 Google Artifact Registry는 리소스를 지속적으로 사용합니다.
정리
이 Codelab 후에는 Google Kubernetes Engine, Google Cloud Trace, Google Artifact Registry에 예상치 못한 요금이 발생하지 않도록 Kubernetes 클러스터를 중지하고 프로젝트를 삭제해야 합니다.
먼저 다음 명령어를 사용하여 클러스터를 삭제합니다.
skaffold delete
명령어 결과
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
클러스터를 삭제한 후 메뉴 창에서 'IAM 및 관리 > '설정'을 클릭한 다음 '종료'를 클릭합니다. 버튼을 클릭합니다.
그런 다음 대화상자의 양식에 프로젝트 ID (프로젝트 이름 아님)를 입력하고 종료를 확인합니다.