이 페이지에서는 Grafana 사용자 인터페이스와 로그 쿼리 API를 모두 사용하여 로그를 쿼리하고 시각화하여 서비스 이벤트와 활동에 대한 유용한 정보를 얻는 방법을 자세히 설명합니다.
Google Distributed Cloud (GDC) 에어 갭에서 배포된 워크로드와 서비스의 로그를 수집한 후 분석을 시작할 수 있습니다. 로그를 분석하려면 유용한 Grafana 패널에서 시각화하고 필터링하거나 프로그래매틱 액세스를 위해 HTTP 또는 gRPC 호출을 사용하여 로그 쿼리 API에서 직접 액세스하면 됩니다.
다음 두 가지 방법 중 하나로 로그에 액세스할 수 있습니다.
- Grafana 패널: Grafana 인스턴스의 로그 패널을 통해 프로젝트의 활동 기록에 대한 유용한 정보를 얻을 수 있습니다. 이 패널을 사용하면 특정 로그를 쿼리하고 정확히 찾아낼 수 있으므로 필요에 맞게 세부적인 데이터 관측 가능성을 제공합니다. Grafana는 워크로드 데이터를 필터링하고 분석하며, 포괄적인 시각화를 위한 맞춤 대시보드와 패널을 만들 수 있는 사용자 친화적인 인터페이스를 제공합니다.
- 로그 쿼리 API: 프로그래매틱 액세스의 경우 프로젝트의 로그 쿼리 API에서 직접 로그를 쿼리합니다. 로그 쿼리 API는 HTTP와 gRPC를 지원하는 비 Kubernetes API로, 자체 엔드포인트를 노출합니다. 표준 API 액세스 방법에 따라 분산 클라우드의 특정 조직 내에서만 이 API에 액세스하세요.
시작하기 전에
Grafana 사용자 인터페이스에서 로그를 쿼리하고 시각화하는 데 필요한 권한을 얻으려면 조직 IAM 관리자 또는 프로젝트 IAM 관리자에게 사전 정의된 조직 Grafana 뷰어 또는 프로젝트 Grafana 뷰어 역할 중 하나를 부여해 달라고 요청하세요. 필요한 액세스 수준과 권한에 따라 조직 또는 프로젝트에서 Grafana 역할을 획득할 수 있습니다.
또는 로그 쿼리 API에서 로그를 쿼리하는 데 필요한 권한을 얻으려면 프로젝트 IAM 관리자에게 프로젝트 네임스페이스에서 로그 쿼리 API 쿼리자 역할을 부여해 달라고 요청하세요.
이러한 역할에 대한 자세한 내용은 IAM 권한 준비를 참고하세요.
로그 쿼리 및 필터링
다음 방법 중 하나를 선택하여 쿼리를 빌드하고 프로젝트 워크로드에서 로그를 필터링합니다.
Grafana 로그 패널
이 섹션에서는 Grafana의 로그 패널을 사용하여 로그에 액세스하는 방법을 설명합니다.
Grafana 엔드포인트 식별
다음 URL은 프로젝트의 Grafana 인스턴스 엔드포인트입니다.
https://GDC_URL/PROJECT_NAMESPACE/grafana
다음을 바꿉니다.
GDC_URL
: GDC의 조직 URL입니다.PROJECT_NAMESPACE
: 프로젝트 네임스페이스예를 들어
org-1
조직의platform-obs
프로젝트에 대한 Grafana 엔드포인트는https://org-1/platform-obs/grafana
입니다.
Grafana 사용자 인터페이스에서 로그 보기
Grafana 사용자 인터페이스에서 로그를 쿼리합니다.
- GDC 콘솔에서 프로젝트를 선택합니다.
- 탐색 메뉴에서 작업 > 로깅을 선택합니다.
Grafana Loki에서 모두 보기를 클릭합니다.
새 페이지에 Grafana 엔드포인트가 열리고 사용자 인터페이스가 표시됩니다.
사용자 인터페이스의 탐색 메뉴에서 탐색 Explore을 클릭하여 Explore 페이지를 엽니다.
탐색 표시줄의 메뉴에서 유니버스 유형에 따라 로그를 가져올 데이터 소스를 선택합니다.
단일 영역 유니버스: 다음 데이터 소스 중 하나를 선택하여 유니버스의 단일 영역에서 로깅 데이터를 표시합니다.
- 작업 로그: 작업 로그를 표시합니다.
- 감사 로그: 감사 로그를 표시합니다.
멀티 영역 유니버스: Grafana는 여러 영역에 연결하여 영역 간 데이터를 표시할 수 있습니다. 로그인한 영역과 관계없이 유니버스의 모든 영역에서 로깅 데이터를 표시하려면 다음 데이터 소스 중 하나를 선택하세요.
- 운영 로그 ZONE_NAME: 특정 영역의 운영 로그를 표시합니다.
- 감사 로그 ZONE_NAME: 특정 영역의 감사 로그를 표시합니다.
또한 단일 대시보드에 교차 영역 데이터 시각화를 표시하고 쿼리에 여러 영역을 추가하려면 데이터 소스로 혼합을 선택합니다.
LogQL(로그 쿼리 언어) 표현식을 사용하여 로그 패널에서 로그를 검색하는 쿼리를 입력합니다. 이 단계는 다음 두 가지 방법 중 하나로 수행할 수 있습니다.
- 대화형 쿼리 빌더 인터페이스를 사용합니다. 그런 다음 쿼리 실행을 클릭합니다.
- 텍스트 필드에 직접 쿼리를 입력하고 Shift+Enter를 눌러 쿼리를 실행합니다.
페이지에 쿼리와 일치하는 로그가 표시됩니다. 로그를 쿼리한 후 내보낼 수 있습니다. 내보내기를 클릭하여 일반 텍스트 또는 CSV 형식으로 로그를 다운로드합니다. 로그의 시간 범위를 선택할 수도 있습니다.
그림 1. Grafana 사용자 인터페이스에서 감사 로그를 쿼리하는 메뉴 옵션
그림 1에서 감사 로그 옵션은 Grafana에서 감사 로그를 가져오는 쿼리를 빌드할 수 있는 인터페이스를 표시합니다.
다양한 로그를 쿼리하는 라벨 및 값의 예는 샘플 쿼리 및 라벨을 참고하세요.
로그의 기간 선택
특정 기간의 로그를 쿼리하려면 다음 단계를 따르세요.
Grafana에서
시간 선택기 메뉴를 클릭합니다.메뉴에서 다음 작업 중 하나를 수행합니다.
- 지난 30분과 같은 상대 시간 범위 옵션을 선택합니다.
- 캘린더에서 특정 날짜와 시간을 선택하고 기간 적용을 클릭하여 맞춤 절대 기간을 설정합니다.
선택적으로 시간 설정 변경을 클릭하여 시간 범위 컨트롤에서 시간대 및 회계연도 설정을 변경할 수 있습니다.
시간 설정은 대시보드별로 저장됩니다. 시간 범위에 대한 쿼리에 관한 자세한 내용은 https://grafana.com/docs/loki/latest/reference/api/#query-loki-over-a-range-of-time을 참고하세요.
로그 쿼리 API
이 섹션에서는 로그 쿼리 API를 사용하여 로그에 액세스하는 방법을 설명합니다.
로그 쿼리 API 엔드포인트 식별
로그 쿼리 API는 감사 및 운영 로그를 쿼리하기 위해 다음 두 엔드포인트를 노출합니다.
감사 로그 엔드포인트:
audit-log-query-api.ORG_DOMAIN
운영 로그 엔드포인트:
operational-log-query-api.ORG_DOMAIN
ORG_DOMAIN
을 조직의 도메인 이름으로 바꿉니다. gdcloud config list
명령어를 사용하여 이 속성을 볼 수 있습니다. 도메인 이름은 org-name.zone.google.gdch.com
구문을 따라야 합니다. 예를 들어 zone1
영역의 테스트 환경에 있는 org-1
라는 조직의 도메인은 org-1.zone1.google.gdch.test
와 같습니다.
로그 쿼리 API에는 다음과 같은 세 가지 엔드포인트 옵션이 있습니다.
- labels: 프로젝트의 모든 라벨을 나열합니다.
- labels/labels/LABEL/values: 프로젝트의 특정 라벨 값을 나열합니다.
- logs: 특정 프로젝트의 로그를 나열합니다.
자세한 내용은 API 문서를 참조하세요.
쿼리 보내기
HTTP 또는 gRPC 클라이언트를 사용하여 로그 쿼리 API 엔드포인트에 쿼리를 보냅니다.
HTTP
안내에 따라 HTTP 클라이언트로 API에 직접 액세스합니다.
kubectl
를 사용하여 인증을 관리하거나 직접 인증을 처리할 수 있습니다.
curl
, wget
또는 직접 만들고 관리하는 HTTP 클라이언트와 같은 HTTP 클라이언트를 사용하여 로그 쿼리 API를 쿼리합니다. 다음 예에서는 curl
도구를 사용하여 API를 쿼리하며 wget
명령어에도 유사한 형식을 사용할 수 있습니다.
cURL 요청을 인증합니다.
- gdcloud CLI를 다운로드하고 설치합니다.
gdcloud
core/organization_console_url
속성을 설정합니다.gdcloud config set core/organization_console_url https://GDC_URL
GDC_URL
을 GDC의 조직 URL로 바꿉니다.-
gdcloud auth login
사용자와 비밀번호를 사용하여 인증하고 로그인합니다.
지정된 계정의 ID 토큰을 환경 변수로 내보냅니다.
export TOKEN="$($HOME/gdcloud auth print-identity-token --audiences=https://LOG_QUERY_API_ENDPOINT)"
LOG_QUERY_API_ENDPOINT
을 로그를 쿼리할 로그 쿼리 API 엔드포인트 및 연결할 도메인으로 바꿉니다. 따라서audiences
플래그의 값은 예를 들어https://operational-log-query-api.org-1.zone1.google.gdch.test
일 수 있습니다.로그인이 성공하면
gdcloud auth print-identity-token
명령어를 통해 cURL 요청에서 승인 헤더를 사용할 수 있습니다. 자세한 내용은 gdcloud auth print-identity-token을 참고하세요.
프로젝트의 모든 라벨을 나열하려면 다음 쿼리를 전송합니다.
curl -H "Authorization: Bearer ${TOKEN}" \ https://LOG_QUERY_API_ENDPOINT/v1/projects/PROJECT_NAMESPACE/labels \ -H "Content-Type: application/json" -v
다음을 바꿉니다.
LOG_QUERY_API_ENDPOINT
: 로그를 쿼리하려는 로그 쿼리 API 엔드포인트입니다.PROJECT_NAMESPACE
: 프로젝트 네임스페이스
프로젝트의 특정 라벨 값을 나열하려면 다음 쿼리를 전송합니다.
curl -H "Authorization: Bearer ${TOKEN}" \ https://LOG_QUERY_API_ENDPOINT/v1/projects/PROJECT_NAMESPACE/labels/labels/LABEL/values \ -H "Content-Type: application/json" -v
다음을 바꿉니다.
LOG_QUERY_API_ENDPOINT
: 로그를 쿼리하려는 로그 쿼리 API 엔드포인트입니다.PROJECT_NAMESPACE
: 프로젝트 네임스페이스LABEL
: 값을 쿼리하려는 특정 라벨입니다.
특정 프로젝트의 로그를 쿼리하려면
logs_filter
쿼리를 구성하고 요청 본문에 포함합니다.curl -X GET -H "Authorization: Bearer ${TOKEN}" \ https://LOG_QUERY_API_ENDPOINT/v1/projects/PROJECT_NAMESPACE/logs \ -H "Content-Type: application/json" -d \ '{"logs_filter": {"labels_equal": {"LABEL": "LABEL_VALUE"}}}' -v
다음을 바꿉니다.
LOG_QUERY_API_ENDPOINT
: 로그를 쿼리하려는 로그 쿼리 API 엔드포인트입니다.PROJECT_NAMESPACE
: 프로젝트 네임스페이스LABEL
: 로그를 쿼리하려는 특정 라벨입니다.LABEL_VALUE
: 로그를 쿼리할 라벨 값입니다.
logs_filter
쿼리를 구성하는 모든 옵션은 API 문서를 참고하세요.
gRPC
gRPC는 프로그래밍 언어 전반에서 널리 지원되며 HTTP 클라이언트에 비해 더 효율적인 통신 방법을 제공합니다.
gRPC를 사용하여 로그를 쿼리하려면 다음 기본 요건을 충족해야 합니다.
- Google에서 제공하는 프로토콜 버퍼를 기반으로 자체 클라이언트 라이브러리를 만듭니다.
- 클라이언트에서 인증을 구현합니다.
- 재시도를 구현합니다.
프로토콜 버퍼에 대한 자세한 내용은 API 문서를 참고하세요.
다음 예는 인증되지 않은 gRPC 클라이언트를 사용하여 Go 프로그램에서 로그를 쿼리하는 방법을 보여줍니다. 이 예에서는 코드 종속 항목을 가져오는 Bazel 빌드 파일이 포함된 golang 패키지를 만들었다고 가정합니다.
다음 코드를
client.go
이라는 Go 프로그램에 저장합니다.package main import ( "context" "crypto/tls" "flag" "fmt" "google.golang.org/grpc/credentials" "google.golang.org/grpc/metadata" pb "<import path to generated log query api protos>/pkg/apis/public/logging/v1/proto" "google.golang.org/grpc" ) var serverAddr = flag.String("server", "localhost:8080", "server address") func main() { flag.Parse() tc := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true}) conn, err := grpc.Dial(*serverAddr, grpc.WithTransportCredentials(tc)) if err != nil { panic(error.Error(fmt.Errorf("create client connection failed: %v", err))) } defer conn.Close() c := pb.NewLogsClient(conn) md := metadata.Pairs("clienttest", "test") ctx := metadata.NewOutgoingContext(context.Background(), md) err = listLabels(ctx, c, "project-foo") if err != nil { panic(error.Error(err)) } if err := listLabelValues(ctx, c, "project-foo", "resource-bar"); err != nil { panic(error.Error(err)) } if err := listLogs(ctx, c, "project-foo", &pb.ListLogsFilter{ LabelsEqual: map[string]string{"resource-bar": "resource-bar-value"}, OrderAscending: true, }); err != nil { panic(error.Error(err)) } } // List all labels for a project. func listLabels(ctx context.Context, c pb.LogsClient, project string) error { lbr := &pb.ListLabelsRequest{ Parent: project, PageSize: 1000, // PageSize can be configured to limit the number of responses per page. } resp, err := c.ListLabels(ctx, lbr) if err != nil { return fmt.Errorf("list labels: %v", err) } fmt.Printf("%v", resp) return nil } // List specific label values for a project. func listLabelValues(ctx context.Context, c pb.LogsClient, project string, label string) error { lbr := &pb.ListLabelValuesRequest{ Parent: project, Label: label, PageSize: 1000, // PageSize can be configured to limit the number of responses per page. } resp, err := c.ListLabelValues(ctx, lbr) if err != nil { return fmt.Errorf("list label values: %v", err) } fmt.Printf("%v", resp) return nil } // List logs for a specific project. func listLogs(ctx context.Context, c pb.LogsClient, project string, lf *pb.ListLogsFilter) error { lbr := &pb.ListLogsRequest{ Parent: project, LogsFilter: lf, PageSize: 5, // PageSize can be configured to limit the number of responses per page. } resp, err := c.ListLogs(ctx, lbr) if err != nil { return fmt.Errorf("list logs: %v", err) } fmt.Printf("logs: %v", resp) return nil }
Go 프로그램을 실행합니다.
go run PATH_TO_API/client.go -server=LOG_QUERY_API_ENDPOINT:443
다음을 바꿉니다.
PATH_TO_API
: API 파일의 경로입니다.LOG_QUERY_API_ENDPOINT
: 로그를 쿼리하려는 로그 쿼리 API 엔드포인트입니다.
서버 플래그를 지정하지 않으면 기본 요청이
localhost
에 도달합니다.
샘플 쿼리 및 라벨
다음은 로그를 쿼리하는 데 사용할 수 있는 기본 라벨입니다.
cluster
: 클러스터의 이름입니다.namespace
: 프로젝트 네임스페이스node
: 노드 이름입니다.pod
: 포드 이름입니다.container
: 컨테이너 이름입니다.
다음 코드 샘플은 라벨과 값을 사용하여 다양한 로그를 쿼리하는 방법을 보여줍니다.
서버 로그를 선택합니다.
{cluster="admin", namespace="kube-system", resources="k8s_container", container="kube-apiserver"}
클러스터 감사 로그를 선택합니다.
{cluster="admin", resources="k8s_audit"}