일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- kubernetes
- terraform
- Terraform Cloud
- devops
- AWS
- vm
- vpc peering
- Java
- 자격증
- cloud function
- gcp
- 우테캠
- 후기
- IAM
- 보안 규칙
- MIG
- cicd
- Python
- interconnect
- Uptime Check
- VAGRANT
- github
- docker
- cloud
- direnv
- Google Cloud Platform
- Clean Code
- cloud armor
- pub/sub
- CentOS
- Today
- Total
EMD Blog
GCP Pub/Sub + Cloud Functions로 Google Chat 알림 채널 구성 본문
모니터링 알림을 받기 위해서는 알림 채널을 설정해 알림을 전달 받을 수 있다. 주로 사용되는 Gmail이나 Slack 같은 경우는 쉽게 가공된 알림 데이터를 전달 받을 수 있지만 Google Chat은 알림 채널로 지원하고 있지 않아 Pub/Sub을 알림 채널로 사용해 Pub/Sub -> Cloud Functions → Webhook → Google Chat 흐름을 직접 구성해야한다.
큰 순서는 다음과 같다.
- 모니터링 알림 채널로 사용할 Pub/Sub 주제를 생성
- 모니터링 알림 채널로 방금 생성한 주제 지정
- 생성한 주제를 트리거로 하는 Cloud Functions를 생성 or Cloud Functions를 생성하고 인증된 호출을 하도록 구독을 수동으로 생성
- 알림을 받을 Google Chat Space를 생성하고 Webhook URL 추가
- Webhook으로 알림 데이터를 보낼 수 있게 Cloud Functions 코드 작성
- 테스트
하나씩 살펴보면
- 모니터링 알림 채널로 사용할 Pub/Sub 주제를 생성
Pub/Sub으로 모니터링 알림을 전달할 것이므로 주제를 제일 먼저 생성해야한다. 주제를 생성하면 다양한 GCP Cloud에서 이 주제에 메세지를 게시할 수 있게 된다. 자세한 내용은 아래 문서 참고
What is Pub/Sub? | Cloud Pub/Sub Documentation | Google Cloud
Pub/Sub의 주제를 생성하려면 아래 명령어를 사용한다.
gcloud pubsub topics create | Google Cloud CLI Documentation
- 모니터링 알림 채널로 방금 생성한 주제 지정
모니터링에서 발생하는 알림은 알림 채널로 전송되며, 현재는 아래와 같은 알림 채널을 지원하고 있다. (문서 참고)
Manage notification channels | Cloud Monitoring | Google Cloud
이 알림의 경우 해당 채널 서비스에 해당하는 REST API 호출하는 방식이기 때문에 데이터가 가공되어 전달될 수도 있다. 예를 들어 알림 채널을 Pub/Sub으로 지정하면 Pub/Sub의 REST API는 데이터를 Base64로 인코딩된 데이터만 받기 때문에 알림 데이터 전달 시 인코딩된 데이터가 전달 된다.
알림 채널을 추가하는 방법은 알림 채널 페이지로 이동해 주제 이름을 입력해주면 된다. 주제 이름은 아래와 같은 형식으로 작성해야 한다.
projects/[PROJECT_ID]/topics/[TOPIC]
이 알림 채널을 설정하는 것은 알림 메세지를 주제에 게시하겠다는 말이기 때문에 서비스 계정에 주제 게시자 역할을 부여해주어야 한다. 역할 부여는 아래 명령어를 사용한다.
gcloud pubsub topics add-iam-policy-binding | Google Cloud CLI Documentation
gcloud pubsub topics add-iam-policy-binding \\
projects/<project_id>/topics/<topic> --role=roles/pubsub.publisher \\
--member=serviceAccount:service-<project_numnber>@gcp-sa-monitoring-notification.iam.gserviceaccount.com
참고로 서비스 계정은 service-<PROJECT_NUMBER>@gcp-sa-monitoring-notification.iam.gserviceaccount.com 이다.
- 생성한 주제를 트리거로 하는 Cloud Functions를 생성 or Cloud Functions를 생성하고 인증된 호출을 하도록 구독을 수동으로 생성
알림 메세지를 Pub/Sub에 게시할 수 있게 되었으니 이제 이 메세지를 Cloud Functions로 보내 가공해야 한다. Cloud Functions로 메세지를 보내는 방법은 두 가지가 존재한다.
[1] 주제에 메세지가 게시될 때마다 이벤트 트리거로 호출되는 Cloud Functions를 생성.
[2] HTTP 트리거 방식의 Cloud Functions를 생성하고 엔드포인트로 메세지를 Push하는 구독 생성.
[1] 방식의 경우 구독이 자동으로 생성되기 때문에 네이밍 규칙을 준수할 수 없게 된다. 그래서 시간이 더 걸리더라도 [2] 방식으로 진행한다. 만약에 네이밍이 상관 없다면 [1] 방식 추천.
Cloud Functions 배포는 아래의 명령어를 사용한다.
gcloud functions deploy | Google Cloud CLI Documentation
배포 시 주의할 점은
- -allow-unauthenticated 옵션을 사용하면 Open API가 되어버리니 주의
- -service-account의 경우 Cloud Functions가 다른 GCP 리소스에 접근할 일이 없으므로 별다른 역할이 필요하지 않음.
- -ingress-settings 옵션은 all 로 설정해야한다. 여기서 internal은 같은 VPC를 뜻하기 때문에 Pub/Sub에서 접근이 안된다.
Cloud Functions를 생성했으면 Function에 메세지를 전달할 구독을 생성해야 한다. 하지만 그 전에 방금 생성한 Function을 호출할 수 있는 권한을 가진 서비스 계정부터 생성해야 한다. 서비스 계정은 아래 명령어로 생성한다.
gcloud iam service-accounts create | Google Cloud CLI Documentation
서비스 계정 생성 후 방금 생성한 Functions에 대한 호출 권한을 부여한다. 호출 권한을 부여하려면 서비스 계정에 roles/cloudfunctions.invoker 역할을 부여해야 한다.
gcloud functions add-iam-policy-binding | Google Cloud CLI Documentation
역할까지 부여했다면 구독을 생성한다. 구독 생성은 아래 명령어를 사용한다.
gcloud pubsub subscriptions create | Google Cloud CLI Documentation
- -push-auth-service-account에 방금 생성한 서비스 계정을 지정하면 된다.
- 알림을 받을 Google Chat Space를 생성하고 Webhook URL 추가
- Google Chat으로 이동해 스페이스 탭 우측의 + 버튼 클릭 후 스페이스 만들기 클릭
- 스페이스 명 입력 후 만들기
- 방금 생성한 스페이스의 대화창 상단의 스페이스 명 클릭 → 웹훅 관리
- 웹훅 명 입력 후 만들기 → URL 복사 (아바타 URL을 지정하면 웹훅 URL 왼쪽 이미지가 변경됨)
- Webhook으로 알림 데이터를 보낼 수 있게 Cloud Functions 코드 작성
Pub/Sub은 REST API로 데이터를 전달 받을 때 base64로 인코딩된 데이터만을 받을 수 있다. 데이터 구조는 아래 문서를 참고하면 된다.
PubsubMessage | Cloud Pub/Sub Documentation | Google Cloud
base64로 인코딩된 데이터를 디코딩 했을 때 데이터 구조는 아래와 같다.
- JSON 예시
{
"incident": {
"incident_id": "0.opqiw61fsv7p",
"scoping_project_id": "internal-project",
"scoping_project_number": 12345,
"url": "<https://console.cloud.google.com/monitoring/alerting/incidents/0.lxfiw61fsv7p?project=internal-project>",
"started_at": 1577840461,
"ended_at": 1577877071,
"state": "closed",
"resource_id": "11223344",
"resource_name": "internal-project gke-cluster-1-default-pool-e2df4cbd-dgp3",
"resource_display_name": "gke-cluster-1-default-pool-e2df4cbd-dgp3",
"resource_type_display_name": "VM Instance",
"resource": {
"type": "gce_instance",
"labels": {
"instance_id": "11223344",
"project_id": "internal-project",
"zone": "us-central1-c"
}
},
"metric": {
"type": "compute.googleapis.com/instance/cpu/utilization",
"displayName": "CPU utilization",
"labels": {
"instance_name": "the name of the VM instance"
}
},
"metadata": {
"system_labels": { "labelkey": "labelvalue" },
"user_labels": { "labelkey": "labelvalue" }
},
"policy_name": "Monitor-Project-Cluster",
"policy_user_labels" : {
"user-label-1" : "important label",
"user-label-2" : "another label"
},
"condition_name": "VM Instance - CPU utilization [MAX]",
"threshold_value": "0.9",
"observed_value": "0.835",
"condition": {
"name": "projects/internal-project/alertPolicies/1234567890123456789/conditions/1234567890123456789",
"displayName": "VM Instance - CPU utilization [MAX]",
"conditionThreshold": {
"filter": "metric.type=\\\\"compute.googleapis.com/instance/cpu/utilization\\\\" resource.type=\\\\"gce_instance\\\\" metadata.system_labels.\\\\"state\\\\"=\\\\"ACTIVE\\\\"",
"aggregations": [
{
"alignmentPeriod": "120s",
"perSeriesAligner": "ALIGN_MEAN"
}
],
"comparison": "COMPARISON_GT",
"thresholdValue": 0.9,
"duration": "0s",
"trigger": {
"count": 1
}
}
},
"documentation": {
"content": "TEST ALERT\\n\\npolicy.name=projects/internal-project/alertPolicies/1234567890123456789\\n\\npolicy.display_name=Monitored-Project-NO-GROUPBY\\n\\ncondition.name=projects/nternal-project/alertPolicies/1234567890123456789/conditions/1234567890123456789\\n\\ncondition.display_name=VM Instance - CPU utilization [MAX]\\n\\nproject=internal-project\\n\\nresrouce.project=internal-project \\n\\nDONE\\n",
"mime_type": "text/markdown"
},
"summary": "CPU utilization for internal-project gke-cluster-1-16-default-pool-e2df4cbd-dgp3 with metric labels {instance_name=gke-cluster-1-default-pool-e2df4cbd-dgp3} and system labels {state=ACTIVE} returned to normal with a value of 0.835."
},
"version": "1.2"
}
각 항목별 설명은 아래와 같다.
- 스키마 구조 v1.2
{
"version": "1.2",
"incident": {
이슈에 관한 정보
"incident_id": 문자열, 이 이슈에 대해 생성된 ID입니다.
"scoping_project_id": 문자열, 측정항목 범위를 호스팅하는 프로젝트 ID입니다.
"scoping_project_number": 숫자, 범위 지정 프로젝트의 프로젝트 번호입니다.
"url": 문자열, 이 이슈에 대한 Google Cloud Console URL입니다
"started_at": 숫자, 이슈가 개설된 시간(Unix epoch 초 단위)입니다.
"ended_at": 숫자, 이슈가 종료된 시간(Unix epoch 초 단위)입니다. state가 closed일 때만 채워집니다.
"state": 문자열, 이슈 상태(open 또는 closed) open이면 ended_at이 null입니다.
"summary": 문자열, 이 이슈에 대해 생성된 텍스트 요약입니다.
"apigee_url": 문자열, Apigee 리소스 유형 Environment 및 Proxy*에만 해당하는 이 이슈에 대한 Apigee URL입니다.
"observed_value": 문자열, 조건이 만료된 경우 알림을 트리거하거나 해결한 관찰된 값이 비어 있을 수 있습니다.
이슈가 개설된 모니터링 리소스에 대한 정보입니다.
"resource": {
"type": 문자열, gce_instance와 같이 알람을 제공하는 모니터링 리소스 유형의 식별자입니다. 모니터링 리소스 목록을 참조하세요.
"labels": 객체, 모니터링 리소스와 연결된 라벨의 키-값 쌍입니다.
},
"resource_type_display_name": 문자열, 모니터링 리소스 유형의 표시 이름입니다.
"resource_id": 문자열, 모니터링 리소스의 인스턴스 ID입니다. resource.labels.instance_id와 동일한 값입니다.
"resource_display_name": 문자열, 모니터링 리소스의 표시 이름입니다.
"resource_name": 문자열, 이 모니터링 리소스의 생성 이름입니다. 다른 필드의 값으로 구성됩니다.
시계열 데이터의 측정항목 유형에 대한 정보입니다.
"metric": {
"type": 문자열, compute.googleapis.com/instance/cpu/utilization과 같이 알림을 받는 측정항목 유형의 식별자입니다.측정항목 목록을 참조하세요.
"displayName": 문자열, 측정항목 유형의 표시 이름입니다.
"labels": 객체, 측정항목과 연결된 라벨의 키-값 쌍입니다.
},
"metadata": {
"system_labels": 객체, 시스템 메타데이터 라벨의 키-값 쌍입니다.
"user_labels": 객체, 사용자 메타데이터 라벨의 키-값 쌍입니다.
},
이슈를 개설/해결한 알림 정책 및 조건에 대한 정보입니다.
값은 관련 AlertPolicy 객체에서 가져옵니다.
"policy_name": 문자열, 알림 정책의 표시 이름입니다.
"policy_user_labels": 객체, 정책에 연결된 사용자 라벨의 키-값 쌍입니다.
"documentation": 객체, Documentation 형식의 삽입된 구조입니다.
"condition": 객체, Condition 형식의 삽입된 구조입니다.
"condition_name": 문자열, 조건의 표시 이름, condition.displayName과 동일한 값입니다.
"threshold_value": 문자열, 이 조건의 임곗값이며 조건이 임곗값 조건이 아닌 경우 비어 있을 수 있습니다.
},
}
코드로 진행해야하는 부분은 다음과 같다.
- 데이터 디코딩
- 필요한 데이터 선별
- 보기 좋게 가공
- Webhook으로 전달
참고로 Webhook은 text로만 데이터를 받는다.
Cloud Functions의 코드는 인라인으로 작성할 수도 있지만 Cloud Storage 경로를 지정할 수도 있다.(CI/CD 적용 가능)
'Public Cloud > GCP' 카테고리의 다른 글
GCP 감사 로그 관련 문서 모음 (0) | 2022.09.03 |
---|---|
GCP KMS (0) | 2022.09.03 |
비공개 Uptime Check 구성 (0) | 2022.09.03 |
GCP GCS 커스텀 도메인 적용 (0) | 2022.09.03 |
GCP Cloud Functions (0) | 2022.09.03 |