주:
- 이 자습서에서는 Oracle Cloud에 액세스해야 합니다. 무료 계정에 등록하려면 Oracle Cloud Infrastructure Free Tier 시작하기를 참조하십시오.
- Oracle Cloud Infrastructure 자격 증명, 테넌시 및 구획에 예제 값을 사용합니다. 실습을 완료했으면 이러한 값을 자신의 클라우드 환경과 관련된 값으로 대체하십시오.
Datadog를 사용하여 PostgreSQL로 Oracle Cloud Infrastructure Database 모니터링
소개
Oracle Cloud Infrastructure(OCI)는 모던 기업의 니즈를 충족하도록 설계된 강력하고 확장성이 뛰어난 클라우드 플랫폼입니다. 컴퓨팅, 스토리지, 네트워킹, 데이터베이스 및 애플리케이션 개발을 위한 포괄적인 서비스 제품군을 제공하며 성능, 보안 및 비용 효율성에 최적화되어 있습니다. OCI는 클라우드 네이티브 및 기존 워크로드를 모두 실행하는 데 이상적이며 기업에게 유연하고 안정적인 인프라를 제공합니다.
Datadog는 조직이 IT 인프라, 애플리케이션 및 서비스에 대한 엔드투엔드 가시성을 확보할 수 있도록 설계된 포괄적인 클라우드 기반 모니터링 및 분석 플랫폼입니다. 동적 하이브리드 클라우드 환경 전반에서 실시간 모니터링, 문제 해결 및 성능 최적화를 지원합니다. Datadog는 광범위한 도구, 플랫폼 및 서비스와 원활하게 통합되어 최신 DevOps 및 IT 운영 팀을 위한 다용도 솔루션입니다.
이 사용지침서에서는 OCI Database with PostgreSQL 및 Datadog 사용자가 OCI Connector Hub 및 OCI Functions를 사용하여 OCI에서 Datadog로 측정지표를 원활하게 전송하기 위한 효율적이고 확장 가능한 솔루션을 설정하는 방법을 보여줍니다.
목표
- 데이터베이스 성능을 실시간으로 모니터링, 경고 및 관찰하여 원활한 작동과 사전 문제 해결을 보장합니다.
필요 조건
-
OCI 테넌시에 액세스합니다.
-
프라이빗 서브넷에 프로비전된 PostgreSQL 시스템이 포함된 OCI 데이터베이스입니다.
-
배스천 호스트(컴퓨트 이미지).
태스크 1: Datadog 계정 생성
-
Datadog 웹 사이트를 사용하여 Datadog 통합 도구에서 계정을 설정합니다. 적합한 환경 설정을 구성하여 필요한 계정 세부정보를 제공하고 에이전트 설정을 완료하십시오.
-
PostgreSQL를 사용하여 OCI 데이터베이스에서 측정항목 및 이벤트를 수집하려면 Datadog 에이전트를 설치합니다. Datadog 에이전트 설정 및 구성에 대한 자세한 내용은 데이터독 에이전트 설정을 참조하십시오. Datadog 에이전트의 문제 해결 및 디버깅에 대한 자세한 내용은 Basic Datadog Agent Usage을 참조하십시오.
-
통합으로 OCI를 선택하고 설치를 계속합니다. 다음 이미지는 Datadog용 OCI 통합의 사후 설치를 보여줍니다.
-
테넌시 추가를 누르고 테넌시 OCID 및 홈 영역 정보를 입력합니다.
작업 2: Datadog 인증 리소스 생성
Oracle Cloud Infrastructure(OCI)에서 Datadog 인증 사용자, 그룹 및 정책을 생성합니다.
-
도메인을 만들려면 Identity로 이동하여
DataDog
라는 도메인을 만듭니다. -
DatadogAuthGroup
이라는 그룹을 생성합니다. -
전자 메일 주소(Datadog Monitoring Tool에 로그인할 때 사용한 것과 동일한 전자 메일)를 사용하여
DatadogAuthUser
라는 사용자를 생성하고DatadogAuthGroup
를 그룹으로 지정합니다. -
사용자 OCID를 복사하여 Datadog OCI 통합 타일의 사용자 OCID 필드에 붙여넣어 사용자 OCID를 구성합니다.
-
API를 설정합니다.
-
프로파일로 이동하여 사용자 이름을 선택합니다.
-
왼쪽 하단에 있는 리소스로 이동하고 API 키를 선택합니다.
-
API 키 추가를 누른 다음 개인 키를 다운로드하고 추가를 누릅니다.
-
구성 파일 미리보기 창을 닫습니다. 필요한 작업이 없습니다.
-
지문 값을 복사하여 Datadog OCI 통합 타일의 지문 필드에 붙여넣습니다.
-
-
개인 키를 구성합니다.
-
텍스트 편집기에서 다운로드한 개인 키 파일(
.pem
)을 열거나 터미널 명령(예: cat)을 사용하여 내용을 확인합니다. -
-----BEGIN PRIVATE KEY-----
및-----END PRIVATE KEY-----
행을 포함하여 전체 키를 복사합니다. -
프라이빗 키를 Datadog OCI 통합 타일의 프라이빗 키 필드에 붙여넣습니다.
-
-
postgresqlinteg
(루트) 컴파트먼트에DataDogPolicy
이라는 정책을 생성합니다. -
수동 편집기 모드에서 정책 작성기를 사용하여 필요한 정책 문을 입력합니다.
Allow group DatadogAuthGroup to read all-resources in tenancy
다음은 테넌시 및 사용자 세부정보를 추가한 후의 샘플 Datadog OCI 통합 타일입니다.
작업 3: OCI 스택 생성
ID 섹션으로 이동하여 루트 컴파트먼트 아래에 정책 스택을 생성합니다. 이를 통해 커넥터 허브는 다음 명령문을 사용하여 측정항목을 읽고 함수를 호출할 수 있습니다.
Allow dynamic-group DatadogAuthGroup to read metrics in tenancy
Allow dynamic-group DatadogAuthGroup to use fn-function in tenancy
Allow dynamic-group DatadogAuthGroup to use fn-invocation in tenancy
Datadog 통합을 위해 ID 정책을 구성하고 OCI에서 측정항목 전달 스택을 배치하려면 다음 작업을 수행하십시오.
작업 3.1: 정책 스택 생성(ORM_policy_stack
)
-
Datadog OCI 통합 타일에서 정책 스택 생성을 누르고 제공된 링크(필요한 Terraform 스크립트 포함)를 사용하고 Oracle 이용약관에 동의해야 합니다.
-
Working Directory 드롭다운 메뉴를 누르고
datadog-oci-orm/policy-setup
을 선택합니다. -
사용자정의 Terraform 제공자 사용을 선택 해제합니다.
-
설명이 포함된 이름(예:
datadog-metrics-policy-setup
)을 입력하고 배치할 컴파트먼트를 선택합니다. -
다음을 누르고 동적 그룹 및 정책의 이름을 지정하거나 기본 이름을 사용하고, 테넌시의 홈 영역이 선택되었는지 확인하고, 생성을 누릅니다.
작업 3.2: 측정항목 전달 스택 생성
리소스가 지정된 컴파트먼트에 배치됩니다. 스택을 실행하는 사용자에게 적절한 액세스 권한이 있는지 확인합니다.
-
Datadog OCI 통합 타일에서 정책 스택 생성을 누르고 Oracle 이용약관에 동의합니다.
-
작업 디렉토리 드롭다운 메뉴를 누르고
datadog-oci-orm/metrics-setup
을 선택한 다음 사용자정의 Terraform 제공자 사용을 선택 해제합니다. -
스택 이름을 지정하고 배치 컴파트먼트를 선택한 후 다음을 누릅니다.
-
테넌시 값은 수정되지 않은 상태로 두고, Datadog API 키를 입력하고, US5 끝점(
ocimetrics-intake.us5.datadoghq.com
)을 선택합니다. -
네트워크 구성의 경우 VCN 생성이 선택되어 있는지 확인하고 VCN 생성에 적합한 컴파트먼트를 선택하십시오.
-
함수 설정 섹션에서 기본 애플리케이션 구성을
GENERIC_ARM
로 유지합니다. OCI Docker 레지스트리 사용자 이름 및 비밀번호(아티팩트 비밀번호)를 입력합니다. -
Service Connector Hub 일괄 처리 크기를 5000으로 설정하고 다음을 누릅니다.
-
Create를 누릅니다.
작업 3.3: 구성 완료
-
Datadog OCI 통합 타일로 돌아가서 구성 생성을 눌러 설정을 완료합니다.
-
이 프로세스는 Datadog 측정항목 및 기능이 OCI와의 통합을 위해 올바르게 구성되었는지 확인합니다.
작업 4: OCI 함수 생성
OCI 콘솔에서 애플리케이션을 생성하려면 다음 단계를 수행하십시오.
-
애플리케이션으로 이동하고 애플리케이션 생성을 선택합니다.
-
애플리케이션 이름을 입력하고 적절한 VCN(가상 클라우드 네트워크) 및 서브넷 세부정보를 선택한 다음 생성을 누릅니다.
-
새로 생성된 애플리케이션에 액세스하려면 리소스에서 시작하기를 선택합니다.
-
Launch Cloud Shell을 누르고 해당 지역에 대한 컨텍스트 사용에서 다음 명령을 복사합니다.
fn list context fn use context <region name>
-
함수의 컴파트먼트 ID를 포함하도록 컨텍스트를 업데이트합니다.
fn update context oracle.compartment-id <compartment-id>
-
사용할 레지스트리의 위치를 포함하도록 컨텍스트를 업데이트합니다.
fn update context registry phx.ocir.io/<tenancy_name>/[YOUR-OCIR-REPO]
주: 컨텍스트에서
phx
을 3자리 지역 코드로 바꿉니다. -
비밀번호로 auth 토큰을 사용하여 레지스트리에 로그인합니다.
docker login -u 'TENACNY_NAME/OCI_USERNAME' phx.ocir.io
-
비밀번호를 묻는 메시지가 표시됩니다. 적절한 암호를 제공합니다.
참고:
phx
를 3자리 지역 코드로 바꿉니다.- Oracle Identity Cloud Service를 사용 중인 경우 사용자 이름은
<tenancyname>/oracleidentitycloudservice/<username>
입니다.
-
hello-world 상용구 함수를 생성합니다.
fn list apps fn init --runtime python datadog
fn init
명령은func.py
,func.yaml
및requirements.txt
의 세 파일이 포함된datadog
이라는 폴더를 생성합니다. -
cd datadog
명령을 실행합니다. -
func.py
를 열고 파일 내용을 다음 코드 조각으로 바꿉니다.# oci-monitoring-metrics-to-datadog version 1.0. # # Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. import io import json import logging import os import re import requests from fdk import response from datetime import datetime """ This sample OCI Function maps OCI Monitoring Service Metrics to the DataDog REST API 'submit-metrics' contract found here: https://docs.datadoghq.com/api/latest/metrics/#submit-metrics """ # Use OCI Application or Function configurations to override these environment variable defaults. api_endpoint = os.getenv('DATADOG_METRICS_API_ENDPOINT', 'not-configured') api_key = os.getenv('DATADOG_API_KEY', 'not-configured') is_forwarding = eval(os.getenv('FORWARD_TO_DATADOG', "True")) metric_tag_keys = os.getenv('METRICS_TAG_KEYS', 'name, namespace, displayName, resourceDisplayName, unit') metric_tag_set = set() # Set all registered loggers to the configured log_level logging_level = os.getenv('LOGGING_LEVEL', 'INFO') loggers = [logging.getLogger()] + [logging.getLogger(name) for name in logging.root.manager.loggerDict] [logger.setLevel(logging.getLevelName(logging_level)) for logger in loggers] # Exception stack trace logging is_tracing = eval(os.getenv('ENABLE_TRACING', "False")) # Constants TEN_MINUTES_SEC = 10 * 60 ONE_HOUR_SEC = 60 * 60 # Functions def handler(ctx, data: io.BytesIO = None): """ OCI Function Entry Point :param ctx: InvokeContext :param data: data payload :return: plain text response indicating success or error """ preamble = " {} / event count = {} / logging level = {} / forwarding to DataDog = {}" try: metrics_list = json.loads(data.getvalue()) logging.getLogger().info(preamble.format(ctx.FnName(), len(metrics_list), logging_level, is_forwarding)) logging.getLogger().debug(metrics_list) converted_event_list = handle_metric_events(event_list=metrics_list) send_to_datadog(event_list=converted_event_list) except (Exception, ValueError) as ex: logging.getLogger().error('error handling logging payload: {}'.format(str(ex))) if is_tracing: logging.getLogger().error(ex) def handle_metric_events(event_list): """ :param event_list: the list of metric formatted log records. :return: the list of DataDog formatted log records """ result_list = [] for event in event_list: single_result = transform_metric_to_datadog_format(log_record=event) result_list.append(single_result) logging.getLogger().debug(single_result) return result_list def transform_metric_to_datadog_format(log_record: dict): """ Transform metrics to DataDog format. See: https://github.com/metrics/spec/blob/v1.0/json-format.md :param log_record: metric log record :return: DataDog formatted log record """ series = [{ 'metric': get_metric_name(log_record), 'type' : get_metric_type(log_record), 'points' : get_metric_points(log_record), 'tags' : get_metric_tags(log_record), }] result = { 'series' : series } return result def get_metric_name(log_record: dict): """ Assembles a metric name that appears to follow DataDog conventions. :param log_record: :return: """ elements = get_dictionary_value(log_record, 'namespace').split('_') elements += camel_case_split(get_dictionary_value(log_record, 'name')) elements = [element.lower() for element in elements] return '.'.join(elements) def camel_case_split(str): """ :param str: :return: Splits camel case string to individual strings """ return re.findall(r'[A-Z](?:[a-z]+|[A-Z]*(?=[A-Z]|$))', str) def get_metric_type(log_record: dict): """ :param log_record: :return: The type of metric. The available types are 0 (unspecified), 1 (count), 2 (rate), and 3 (gauge). Allowed enum values: 0,1,2,3 """ return 0 def get_now_timestamp(): return datetime.now().timestamp() def adjust_metric_timestamp(timestamp_ms): """ DataDog Timestamps should be in POSIX time in seconds, and cannot be more than ten minutes in the future or more than one hour in the past. OCI Timestamps are POSIX in milliseconds, therefore a conversion is required. See https://docs.datadoghq.com/api/latest/metrics/#submit-metrics :param oci_timestamp: :return: """ # positive skew is expected timestamp_sec = int(timestamp_ms / 1000) delta_sec = get_now_timestamp() - timestamp_sec if (delta_sec > 0 and delta_sec > ONE_HOUR_SEC): logging.getLogger().warning('timestamp {} too far in the past per DataDog'.format(timestamp_ms)) if (delta_sec < 0 and abs(delta_sec) > TEN_MINUTES_SEC): logging.getLogger().warning('timestamp {} too far in the future per DataDog'.format(timestamp_ms)) return timestamp_sec def get_metric_points(log_record: dict): """ :param log_record: :return: an array of arrays where each array is a datapoint scalar pair """ result = [] datapoints = get_dictionary_value(dictionary=log_record, target_key='datapoints') for point in datapoints: dd_point = {'timestamp': adjust_metric_timestamp(point.get('timestamp')), 'value': point.get('value')} result.append(dd_point) return result def get_metric_tags(log_record: dict): """ Assembles tags from selected metric attributes. See https://docs.datadoghq.com/getting_started/tagging/ :param log_record: the log record to scan :return: string of comma-separated, key:value pairs matching DataDog tag format """ result = [] for tag in get_metric_tag_set(): value = get_dictionary_value(dictionary=log_record, target_key=tag) if value is None: continue if isinstance(value, str) and ':' in value: logging.getLogger().warning('tag contains a \':\' / ignoring {} ({})'.format(key, value)) continue tag = '{}:{}'.format(tag, value) result.append(tag) return result def get_metric_tag_set(): """ :return: the set metric payload keys that we would like to have converted to tags. """ global metric_tag_set if len(metric_tag_set) == 0 and metric_tag_keys: split_and_stripped_tags = [x.strip() for x in metric_tag_keys.split(',')] metric_tag_set.update(split_and_stripped_tags) logging.getLogger().debug("tag key set / {} ".format (metric_tag_set)) return metric_tag_set def send_to_datadog (event_list): """ Sends each transformed event to DataDog Endpoint. :param event_list: list of events in DataDog format :return: None """ if is_forwarding is False: logging.getLogger().debug("DataDog forwarding is disabled - nothing sent") return if 'v2' not in api_endpoint: raise RuntimeError('Requires API endpoint version "v2": "{}"'.format(api_endpoint)) # creating a session and adapter to avoid recreating # a new connection pool between each POST call try: session = requests.Session() adapter = requests.adapters.HTTPAdapter(pool_connections=10, pool_maxsize=10) session.mount('https://', adapter) for event in event_list: api_headers = {'Content-type': 'application/json', 'DD-API-KEY': api_key} logging.getLogger().debug("json to datadog: {}".format (json.dumps(event))) response = session.post(api_endpoint, data=json.dumps(event), headers=api_headers) if response.status_code != 202: raise Exception ('error {} sending to DataDog: {}'.format(response.status_code, response.reason)) finally: session.close() def get_dictionary_value(dictionary: dict, target_key: str): """ Recursive method to find value within a dictionary which may also have nested lists / dictionaries. :param dictionary: the dictionary to scan :param target_key: the key we are looking for :return: If a target_key exists multiple times in the dictionary, the first one found will be returned. """ if dictionary is None: raise Exception('dictionary None for key'.format(target_key)) target_value = dictionary.get(target_key) if target_value: return target_value for key, value in dictionary.items(): if isinstance(value, dict): target_value = get_dictionary_value(dictionary=value, target_key=target_key) if target_value: return target_value elif isinstance(value, list): for entry in value: if isinstance(entry, dict): target_value = get_dictionary_value(dictionary=entry, target_key=target_key) if target_value: return target_value def local_test_mode(filename): """ This routine reads a local json metrics file, converting the contents to DataDog format. :param filename: cloud events json file exported from OCI Logging UI or CLI. :return: None """ logging.getLogger().info("local testing started") with open(filename, 'r') as f: transformed_results = list() for line in f: event = json.loads(line) logging.getLogger().debug(json.dumps(event, indent=4)) transformed_result = transform_metric_to_datadog_format(event) transformed_results.append(transformed_result) logging.getLogger().debug(json.dumps(transformed_results, indent=4)) send_to_datadog(event_list=transformed_results) logging.getLogger().info("local testing completed") """ Local Debugging """ if __name__ == "__main__": local_test_mode('oci-metrics-test-file.json')
-
다음 코드로
func.yaml
를 업데이트합니다.DATADOG_TOKEN
를 Datadog API 키로 바꾸고DATADOG_HOST
를 REST 끝점https://http-intake.logs.datadoghq.com/v1/input
로 바꿉니다. REST 끝점에 대한 자세한 내용은 로그 수집 및 통합을 참조하십시오.schema_version: 20180708 name: datadogapp version: 0.0.1 runtime: python entrypoint: /python/bin/fdk /function/func.py handler memory: 1024 timeout: 120 config: DATADOG_HOST: https://http-intake.logs.datadoghq.com/v1/input DATADOG_TOKEN: ZZZZZzzzzzzzzzz
-
다음 코드로
requirements.txt
를 업데이트합니다.fdk dattime requests oci
-
다음 명령을 실행하여 응용 프로그램을 생성하고 함수를 배치하여 설정을 완료합니다.
fn create app datadog01 --annotation oracle.com/oci/subnetIds='["Provide your subnet OCID"]'
-
다음 명령을 실행하여 설정을 완료하는 함수를 배치합니다.
fn -v deploy --app datadog
작업 5: OCI Connector Hub 설정
-
OCI 콘솔로 이동하여 로깅, 커넥터로 이동하고 커넥터 생성을 누릅니다.
-
소스를 모니터링으로, 대상을 함수로 설정합니다.
-
소스 접속 구성에서 적합한 측정항목 컴파트먼트 및 네임스페이스를 선택합니다. 데이터베이스 모니터링의 경우
oci_postgresql
를 예로 들 수 있습니다. -
대상 구성에서 작업 4에 생성된 구획, 함수 애플리케이션 및 함수를 선택합니다.
-
메시지가 표시되면 생성을 눌러 필요한 정책을 생성합니다.
-
생성을 눌러 OCI Connector Hub 설정을 완료합니다.
작업 6: Datadog에서 측정항목 보기
이제 OCI 커넥터 허브가 함수를 트리거하도록 구성되어 새 측정항목이 감지될 때마다 Datadog로 측정항목을 수집할 수 있습니다. Datadog 통합 타일에서 측정항목으로 이동하고 요약을 검토하여 OCI 관련 측정항목을 봅니다.
Datadog 통합 타일에서 탐색기를 눌러 필요한 OCI 측정항목을 분석하고 필요에 따라 선택합니다.
문제 해결
측정항목 요약 페이지에 데이터가 나타나지 않으면 로그 사용을 선택하여 함수가 로그를 검토하고 문제를 디버그할 수 있도록 로깅을 사용으로 설정합니다.
확인
- 작성자 - Kaviya Selvaraj(수석 멤버 기술 직원)
추가 학습 자원
docs.oracle.com/learn에서 다른 실습을 탐색하거나 Oracle Learning YouTube 채널에서 더 많은 무료 학습 콘텐츠에 액세스하세요. 또한 Oracle Learning Explorer가 되려면 education.oracle.com/learning-explorer을 방문하십시오.
제품 설명서는 Oracle Help Center를 참조하십시오.
Monitor Oracle Cloud Infrastructure Database with PostgreSQL using Datadog
G28861-01
Copyright ©2025, Oracle and/or its affiliates.