어바웃피싱 · 플랫폼개발팀 요청

빌드 알림에 dev · stage · prod 를 구분해서 표시하기

구글챗 빌드봇 전체 채널에 오는 Cloud Build 알림이 지금은 어느 환경 빌드인지 카드를 열어야 알 수 있다. 알림 카드에 환경을 앞세워 표시하고, 실패도 빠짐없이 오게 만드는 작업이다. 아래 순서대로만 하면 된다. 중간에 판단이 필요한 것은 8번에 따로 모아 뒀다. 거기 있는 것은 정하지 말고 물어봐 주면 된다.

요청 서현일 (CPO)
수행 정지섭
대상 GCP 프로젝트 aboutfishingproduct
예상 반나절 (선택 작업 제외)

차례

배경

왜 하는가

지금 알림은 첫 줄이 전부 ✅ Build Succeeded 라서 채팅 목록에서 전부 똑같이 보인다. 환경을 알려면 카드를 열고 트리거 이름을 읽어야 하는데, 이름 규칙이 저장소마다 다르다. platform 저장소는 운영을 release 라고 부르고 booking 저장소는 prod 라고 부른다.

여기에 더해, 채널에서 확인한 최근 알림 16건이 전부 성공이라 빌드가 실패했을 때 알림이 오는지 자체가 확인되지 않았다. 안 온다면 지금 우리는 빌드 실패를 못 보고 있는 것이다.

이 작업이 끝나면 채팅 목록만 훑어도 운영에 나간 빌드와 개발 빌드가 갈리고, 실패가 눈에 띈다. 배포 공지 채널(전사_배포공지)의 자동화도 이 구분 위에 올린다.

오늘(9/9) 주의

오늘은 론칭 컷오버 날이다. 운영(prod·release) 트리거는 오늘 건드리지 않는다. 아래 2단계까지만 오늘 하고, 3단계부터는 9/10 이후에 한다. 순서를 그렇게 짜 뒀다.

현황

지금 확인된 것

구글챗 빌드봇 전체 채널(spaces/AAAAXL2bfc8)에서 직접 읽어 확인한 내용이다. 알림을 보내는 것은 Cloud Build Alert 라는 이름의 앱이고, 카드 형태로 온다.

확인된 트리거 9개

트리거저장소빌드 기준환경(확인 필요)
platform-svc-release-buildaboutfishing-platform태그 (v0.2.x)prod
platform-map-release-buildaboutfishing-platform태그prod
platform-booking-release-buildaboutfishing-platform태그prod
platform-test-buildaboutfishing-platformmain 브랜치dev 또는 test
platform-dev-buildaboutfishing-platformmain 브랜치dev
booking-api-prod-buildaboutfishing-booking-api태그 (v2.54.0)prod
booking-api-stg-buildaboutfishing-booking-apimain 브랜치stage
booking-partners-stg-buildaboutfishing-booking-partnersmain 브랜치stage
booking-partners-test-buildaboutfishing-booking-partnersmain 브랜치dev 또는 test

회색이 운영으로 보이는 것들이다. 이 표의 환경 값은 이름으로 추정한 것이라 1단계에서 실제 배포 대상을 보고 확정해야 한다. 목록에 없는 트리거가 더 있으면 같이 처리한다.

지금 오는 카드

✅ Build Succeeded
Project: aboutfishingproduct / Trigger: booking-api-prod-build
Repository: aboutfishing-booking-api
Branch: N/A
Tag: v2.54.0
Build ID: edc45d6d-6cf8-4404-910e-1cd002f62686
Finished: 2026. 9. 9. AM 11:52:56
[ View Build Logs ]

고칠 점 · 첫 줄에 환경이 없다 / Project 는 하나뿐이라 매번 같은 값이다 / 태그 빌드인데 Branch: N/A 가 뜬다 / Build ID 36자는 아무도 안 읽는다 / 소요 시간이 없다 / 실패했을 때 어디서 깨졌는지가 없다.

작업

작업 순서

0단계부터 5단계까지가 필수, 6·7단계는 선택이다. 각 단계마다 끝난 걸 아는 법을 적어 뒀다.

gcloud config set project aboutfishingproduct
gcloud config set account hiseo@aboutfishing.kr
0단계알림을 보내는 것이 무엇인지 찾는다먼저 해야 나머지가 정해진다

Cloud Build 는 빌드 상태가 바뀔 때마다 cloud-builds 라는 Pub/Sub 토픽에 메시지를 넣는다. 그걸 누가 받아서 챗으로 보내고 있는지 찾는다.

gcloud pubsub topics list-subscriptions cloud-builds
gcloud pubsub subscriptions describe [위에서 나온 구독 이름]
gcloud run services list
gcloud functions list

구독의 pushEndpoint 에 적힌 주소가 카드를 만드는 곳이다. 둘 중 하나일 것이다.

  • 직접 만든 함수나 서비스 — 카드 JSON 을 만드는 코드가 그 안에 있다. 그 코드 한 곳만 고치면 된다.
  • Cloud Build 공식 notifier(cloud-build-notifiers) — Cloud Run 서비스로 떠 있고 설정 파일이 GCS 버킷에 있다. 그 설정의 filter 와 template 을 고친다.

끝난 걸 아는 법 · 카드 문구 Build Succeeded 를 검색해서 그 문자열이 있는 파일이나 코드를 찾았으면 된다.

같이 확인할 것 · 그 코드나 설정이 성공만 걸러서 보내고 있는지. status == 'SUCCESS' 같은 조건이 있으면 지금 실패 알림이 안 오고 있다는 뜻이다. 4단계에서 고친다.

1단계각 트리거가 실제로 어디에 배포하는지 확정한다

이름이 아니라 빌드 구성 파일을 보고 정한다. 배포 대상(Cloud Run 서비스 이름, 네임스페이스, 버킷 등)이 운영인지 스테이지인지 개발인지 확인한다.

gcloud builds triggers list --format="table(name,filename,github.push.tag,github.push.branch)"

현황 표의 9개 각각에 prod / stage / dev 중 하나를 확정한다. test 와 dev 를 굳이 나눌 필요가 없으면 둘 다 dev 로 묶는다. 표시는 세 가지만 쓴다.

끝난 걸 아는 법 · 트리거 9개(또는 그 이상) 전부에 세 값 중 하나가 붙었고, 애매한 게 하나도 안 남았으면 된다.

2단계dev 트리거 하나로 먼저 시험한다여기서 함정이 하나 있다
먼저 읽을 것

Cloud Build 는 트리거에 정의했는데 빌드 구성 파일에서 안 쓰는 대체 변수가 있으면 빌드를 실패시킨다. 그래서 _ENV 를 넣기만 하고 cloudbuild.yaml 을 안 고치면 그 트리거의 빌드가 깨진다. 운영 트리거에서 이걸 처음 겪으면 안 되니까 dev 하나로 먼저 확인한다.

피하는 방법은 둘 중 하나다. ① 해당 저장소 cloudbuild.yaml 에 아래를 넣는다. ② 트리거 수정 화면의 대체 변수 영역에 있는 느슨한 적용 옵션을 켠다.

options:
  substitution_option: ALLOW_LOOSE

platform-dev-build 하나에만 변수를 넣고 빌드를 돌려 본다.

gcloud builds triggers export --trigger=platform-dev-build --destination=platform-dev-build.yaml

# 파일을 열어 아래 두 줄을 substitutions 아래에 추가한다
#   _ENV: dev
#   _SVC: 플랫폼

gcloud builds triggers import --source=platform-dev-build.yaml
gcloud builds triggers run platform-dev-build --branch=main

끝난 걸 아는 법 · 빌드가 성공하고(실패하면 위 ALLOW_LOOSE 를 안 넣은 것이다) 채널에 평소대로 알림이 온다. 이 시점에는 카드 모양이 아직 그대로여도 정상이다.

잘못되면 · 그 트리거의 빌드만 실패한다. 운영에는 영향이 없다. 되돌리는 법은 아래 5번에 있다.

3단계나머지 트리거에 같은 변수를 넣는다9/10 이후

2단계가 확인되면 나머지에도 넣는다. 저장소별로 cloudbuild.yaml 의 ALLOW_LOOSE 를 먼저 반영한 뒤에 트리거를 고친다.

트리거_ENV_SVC (카드에 표시될 이름)
platform-svc-release-buildprod플랫폼 공통
platform-map-release-buildprod지도
platform-booking-release-buildprod예약
platform-test-builddev플랫폼
platform-dev-builddev플랫폼
booking-api-prod-buildprod예약 API
booking-api-stg-buildstage예약 API
booking-partners-stg-buildstage선주
booking-partners-test-builddev선주

_SVC 의 한글 이름은 예시다. 1단계에서 확인한 실제 서비스에 맞게 바꿔도 된다. 카드에 그대로 찍히는 값이라 개발을 모르는 사람이 읽을 이름으로 쓴다.

끝난 걸 아는 법 · 아래 명령으로 전부 값이 찍히는지 본다. 빈 것이 있으면 안 된다.

gcloud builds triggers list --format="table(name, substitutions._ENV, substitutions._SVC)"

운영 트리거는 태그를 밀어야 돌기 때문에 바로 확인이 어렵다. 값이 들어간 것만 위 명령으로 보고, 실제 카드는 다음 릴리즈 때 확인한다.

4단계카드 모양을 바꾸고, 실패도 보내게 한다

0단계에서 찾은 곳을 고친다. 새 카드 규격은 아래 새 카드 규격 에 필드 대응표와 JSON 예시로 적어 뒀다. 두 가지를 같이 한다.

  1. 카드 제목 맨 앞에 환경 배지를 넣고, 부제에 소요 시간을 넣는다.
  2. 성공 외에 FAILURE · TIMEOUT · INTERNAL_ERROR · CANCELLED 도 보내게 한다. QUEUED 와 WORKING 은 보내지 않는다.

끝난 걸 아는 법 · 실패 카드를 실제로 눈으로 본다. 빌드를 일부러 깨뜨릴 필요 없이 Pub/Sub 에 테스트 메시지를 하나 넣으면 된다.

gcloud pubsub topics publish cloud-builds \
  --attribute=buildId=test-0001,status=FAILURE \
  --message='{"id":"test-0001-aaaa-bbbb-cccc-000000000001","projectId":"aboutfishingproduct","status":"FAILURE","logUrl":"https://console.cloud.google.com/cloud-build/builds?project=aboutfishingproduct","startTime":"2026-09-10T02:50:00Z","finishTime":"2026-09-10T02:51:04Z","substitutions":{"TRIGGER_NAME":"booking-api-prod-build","REPO_NAME":"aboutfishing-booking-api","TAG_NAME":"v2.54.0","_ENV":"prod","_SVC":"예약 API"}}'

테스트 메시지를 보내면 실제 빌드가 도는 것이 아니라 알림만 한 건 간다. 채널에 test-0001 이 붙은 실패 카드가 뜨면 성공이다. 확인 후 그 메시지는 채널에서 지운다.

5단계환경이 없는 빌드를 티 나게 만든다

_ENV 가 비어 있으면 ⚠️ 환경 미지정 으로 표시하게 한다. 앞으로 누가 트리거를 새로 만들면서 변수를 빠뜨리면 이 표시로 바로 드러난다. 이게 없으면 몇 달 뒤에 조용히 틀린 채로 돌아간다.

끝난 걸 아는 법 · 위 테스트 메시지에서 _ENV 를 빼고 다시 보내 본다. 환경 미지정으로 떠야 한다.

6단계dev · stage 알림을 다른 방으로 보낸다선택

지금 알림의 절반 이상이 dev·stage 다. 운영만 빌드봇 전체 에 남기고 나머지는 새 스페이스로 보낸다. 보내는 쪽에서 _ENV 값에 따라 웹훅 주소만 갈라 주면 된다.

새 스페이스와 웹훅 주소는 요청자가 만들어 전달한다. 만들지 여부는 8번을 보고 정한다.

7단계같은 태그의 빌드를 한 줄로 묶는다선택

릴리즈 한 번에 svc·map·booking 세 건이 따로 뜬다. 챗 웹훅 주소 뒤에 스레드 키를 붙이면 같은 태그끼리 한 스레드로 묶인다.

[웹훅 주소]&threadKey=[저장소]-[태그]&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD

끝난 걸 아는 법 · 다음 릴리즈에서 세 건이 한 스레드 안에 붙어서 온다.

규격

새 카드 규격

환경 배지

_ENV 값카드에 찍히는 것
prod🟥 PROD
stage🟨 STAGE
dev⬜ DEV
없거나 그 밖의 값⚠️ 환경 미지정

구글챗 카드는 글자 색을 바꿀 수 없어서 이모지로 구분한다. 채팅 목록 미리보기에 카드 제목이 뜨므로 배지는 반드시 제목 맨 앞에 둔다.

필드 대응표

왼쪽이 카드에서 보이는 자리, 오른쪽이 Pub/Sub 메시지에서 읽을 값이다.

카드 자리예시어디서 읽나
제목 · 배지🟥 PRODsubstitutions._ENV → 위 배지 표
제목 · 서비스예약 APIsubstitutions._SVC. 없으면 substitutions.REPO_NAME
제목 · 버전v2.54.0substitutions.TAG_NAME. 없으면 BRANCH_NAME + 공백 + SHORT_SHA
제목 · 실패 표시— 빌드 실패status 가 SUCCESS 가 아닐 때만 붙인다. 성공이면 아무것도 안 붙인다
부제빌드 성공 · 2분 12초 · 11:52 종료status 한글 표기 + (finishTime − startTime) + finishTime 을 한국 시각으로
환경prodsubstitutions._ENV
저장소aboutfishing-booking-apisubstitutions.REPO_NAME
트리거booking-api-prod-buildsubstitutions.TRIGGER_NAME
빌드edc45d6did 의 앞 8자
깨진 단계 (실패일 때만)Step 3 (docker build)steps[] 중 status 가 SUCCESS 가 아닌 첫 번째. 순번과 name 또는 id
지금 운영 (prod 실패일 때만)직전 버전 그대로입니다. 이번 것은 안 나갔습니다고정 문구
버튼로그 보기logUrl

빼는 것 · Project(프로젝트가 하나뿐이라 매번 같다) · Branch 가 없을 때의 N/A 줄(태그 빌드면 태그만 보이면 된다) · Build ID 뒷자리.

보이는 모습

성공

🟥 PROD · 예약 API v2.54.0
빌드 성공 · 2분 12초 · 11:52 종료

환경     prod
저장소   aboutfishing-booking-api
트리거   booking-api-prod-build
빌드     edc45d6d

[ 로그 보기 ]

실패

🟥 PROD · 예약 API v2.54.0 — 빌드 실패
Step 3 (docker build) 에서 실패 · 1분 04초

환경        prod
지금 운영   직전 버전 그대로입니다. 이번 것은 안 나갔습니다
저장소      aboutfishing-booking-api
트리거      booking-api-prod-build
빌드        edc45d6d

[ 로그 보기 ]

개발

⬜ DEV · 플랫폼 main a1b2c3d
빌드 성공 · 1분 41초 · 11:05 종료
...

보내는 JSON

구글챗 웹훅에 보내는 본문이다. 대괄호 부분만 위 대응표대로 채우면 된다.

{
  "cardsV2": [{
    "cardId": "build-status",
    "card": {
      "header": {
        "title": "[배지] · [서비스] [버전][실패표시]",
        "subtitle": "[상태] · [소요] · [종료시각] 종료"
      },
      "sections": [{
        "widgets": [
          { "decoratedText": { "topLabel": "환경",   "text": "[_ENV]" } },
          { "decoratedText": { "topLabel": "저장소", "text": "[REPO_NAME]" } },
          { "decoratedText": { "topLabel": "트리거", "text": "[TRIGGER_NAME]" } },
          { "decoratedText": { "topLabel": "빌드",   "text": "[id 앞 8자]" } },
          { "buttonList": { "buttons": [
              { "text": "로그 보기", "onClick": { "openLink": { "url": "[logUrl]" } } }
          ]}}
        ]
      }]
    }
  }]
}

실패일 때는 환경 바로 아래에 깨진 단계 와 지금 운영 두 줄을 같은 형태로 끼워 넣는다.

검수

끝났는지 확인하는 법

아래가 전부 확인되면 끝난 것이다. 요청자에게는 이 목록에 체크한 결과와 카드 스크린샷 두 장(성공·실패)만 주면 된다.

복구

되돌리는 법

무엇이 잘못됐나어떻게 되돌리나
트리거에 변수를 넣었더니 빌드가 실패한다ALLOW_LOOSE 가 빠진 것이다. 저장소의 cloudbuild.yaml 에 넣거나, 트리거에서 방금 넣은 _ENV·_SVC 두 줄을 지우고 다시 import 한다
카드가 깨져서 온다알림 보내는 쪽을 직전 버전으로 되돌린다. Cloud Run 이면 이전 리비전으로 트래픽을 돌린다
알림이 아예 안 온다구독이 살아 있는지, 보내는 서비스에 오류 로그가 있는지 본다. 빌드 자체는 알림과 무관하게 정상 동작한다
알림이 두 번씩 온다구독이 둘이거나 예전 것을 안 끄고 새로 붙인 것이다. 하나만 남긴다

이 작업은 전부 알림 쪽이다. 2단계의 대체 변수만 빌드에 닿고, 그것도 ALLOW_LOOSE 하나로 막힌다. 서비스 배포 자체에는 영향이 없다.

확인 요청

물어보고 진행할 것

아래는 정하지 말고 요청자(서현일)에게 물어봐 주면 된다. 나머지는 위 순서대로 진행하면 된다.

번호물어볼 것왜 필요한가
1dev 와 test 를 나눌지, 둘 다 dev 로 묶을지배지를 세 개로 할지 네 개로 할지가 갈린다. 넷이 되면 목록에서 구분이 흐려진다
2dev·stage 알림을 별도 스페이스로 뺄지 (6단계)뺀다면 새 스페이스와 웹훅 주소를 요청자가 만들어 준다
3운영 빌드 실패 시 멘션을 걸지, 건다면 누구에게지금은 성공과 실패가 같은 무게로 흘러간다
4_SVC 에 넣을 한글 서비스 이름3단계 표의 이름은 예시다. 카드에 그대로 찍힌다
5앱(안드로이드·iOS) 빌드는 어디서 도는지확인된 트리거 9개는 전부 웹·서버다. 앱 빌드가 다른 시스템에서 돌고 있다면 그쪽도 같은 방식으로 맞춰야 한다
6릴리즈 빌드가 끝나면 실제 서비스 반영이 자동인지 수동인지빌드 성공을 배포 완료로 볼 수 있는지가 여기서 갈린다. 전사_배포공지 자동화의 전제다

작성 2026-09-09. 트리거 목록과 카드 형식은 구글챗 빌드봇 전체 채널에서 직접 읽어 확인한 것이고, 각 트리거의 환경 값은 이름으로 추정한 것이라 1단계에서 확정이 필요하다.