Skip to main content Link Menu Expand (external link) Document Search Copy Copied

created at 2025-01-18

Table of contents

  1. 1. 빌드 & 모니터링 자동화
    1. MODULE TO BUILD
    2. JIB
    3. GRAFANA
  2. 2. Slack List Notification(upload to actions marketplace)
  3. 3. K8S 롤아웃 자동 트래킹 (image pullback off 에러, 런타임 시 발생한 에러들 알 수 있기 위함)
  4. 3. Slack Message Update
  5. Appendix

1. 빌드 & 모니터링 자동화

MODULE TO BUILD

  • 변경된 파일 목록들 가져와서 공통 모듈이 변경되면 해당 모듈로부터 파생된 다른 모듈들 전부 deploy list 에 넣기.
  • 만약 특정 하위 모듈만 변경되면 해당 모듈만 list 에 추가. 여기서도 추가 반복되는 작업이 발생. (자꾸 빌드 머신이 죽음 -> 리붓 + git runner start cmd 실행 -> 다시 idle 확인) 귀찮아서 다음과 같이 자동화시킴. aws lambda 로 instance reboot, git runner start cmd 실행 자동화, cronjob 으로 매일 리붓, aws api gateway 연결해서 restapi GET 보내면 자동 리붓하도록 만듬. 그래서 버튼 딸깍으로 정상화 가능. 근데 HTTP api gateway inbound traffic 제한 못시켜서(ACL X) ALB 랑 lambda 연결시켜야 할 듯.

JIB

jib 로 docker image build + ./gradlew build + Dockerfile 없이 그냥 ./gradlew jib 이 명령어 하나로 build + image push 하도록. 근데 jib 로 하니까 파일 COPY 했을 때 해시 값이 변경되는 문제가 발생(정상 COPY X). 그래서 copy 할 때 tar 로 압축해서 COPY 하도록 변경.

GRAFANA

cronjob 배치 상태 체크 위해 grafana 에 batch db 에서 데이터 가져와서 시간 별 상황 표시. 근데 만약 job repo 에 넣지 않도록 job 설정해 놨으면 못읽음. 그래서 좀 더 정확하게 할려면 k8s cronjob 로그 읽고 저장할 수 있도록 prometheus 랑 연동하는게 좋을듯? 추가적으로 button 클릭 시 restapi 전송하는 플러그인 찾는중.

2. Slack List Notification(upload to actions marketplace)

img_2.png

뭔가 git action 을 사용하다보면 중간 단계들을 slack 으로 알림을 받아야할 때가 많음. 메세지 전송 스크립트가 너무 귀찮아서 공통 모듈로 만들어서 쓰는데 이마저도 가져와서 chmod +x 실행권한 추가해야해서 귀찮음.

그래서 그냥 git actions marketplace 에 올려놓고 가져와서 편하게 아래와 같이 쓸 수 있도록 수정. 다만 수정이 조금 귀찮을 수 있음. 이건 정말 공통적으로 사용하는 스크립트만 마켓에 올리는 것이 좋을 것 같음.

  - name: Send Message to Slack with Building Modules
    uses: ghkdqhrbals/slack-list@v1.0.12
    with:
      slack-webhook-url: $
      actor: $
      messages: '$' # json string list syntax
      message-title: '개발 수동 배포 시작 (Version: $)'
      color: '#3bb143'

드래프트 repo : https://github.com/ghkdqhrbals/slack-list

git repo root 에 actions.yaml 만들어서 draft 생성 후 release 한 뒤 use 로 해당 액션 가져와서 사용할 수 있음.

3. K8S 롤아웃 자동 트래킹 (image pullback off 에러, 런타임 시 발생한 에러들 알 수 있기 위함)

img_2.png

원래는 kubectl apply -f …deployment.yaml 하면 파드 뜰 때 런타임 시 발생하는 오류에 대처못함. 그래서 retry 몇 번 이상되면 slack 알림오도록 할려고 했음.

하지만 복잡도와 유지보수시간은 비례해서 그냥 롤아웃에 걸리는 시간에 타임리밋 걸어놓고 초과하면 실패오도록 설정.

rollout 상태관찰 잡의 concurrency 는 하나로 설정하는게 좋음. 아니면 다른 잡 오면 cancel-in-progress: true 추가해서 잡 멈추고 최신 잡 실행하는것도 좋음.

  - name: Check Rollout Status
    run: |
      rollout_data='$'
      echo "Rollout data: $rollout_data"

      chmod +x ./scripts/send_slack_message.sh


      for deployment_info in $(echo "$rollout_data" | jq -c '.[]'); do

        # extra logics
      
        echo "Module: $MODULE"
        echo "Deployment Name: $DEPLOYMENT_NAME"
        echo "Franchise: $FRANCHISE"
        pids=()

        # 백그라운드에서 실행
        {
          echo "Checking rollout status for $MODULE ($DEPLOYMENT_NAME in $FRANCHISE namespace)"
          OUTPUT=$(/usr/local/bin/kubectl rollout status deployment/$DEPLOYMENT_NAME -n $FRANCHISE --timeout=10m 2>&1)
          STATUS=$?

          if [[ $STATUS -ne 0 ]]; then
          echo "Rollout failed for deployment: $DEPLOYMENT_NAME"
             ./scripts/send_slack_message.sh "$" \
               "[DEV] $MODULE 롤아웃 실패" \
               "$" \
               "Deployment Bot" \
               ":rocket:"
          else
             echo "Rollout succeeded for deployment: $DEPLOYMENT_NAME"
             ./scripts/send_slack_message.sh "$" \
               "[DEV] $MODULE 롤아웃 완료" \
               "$" \
               "Deployment Bot" \
               ":rocket:"
          fi

        } & 
        pids+=($!)
      done

      echo "백그라운드 프로세스 ID : ${pids[@]}"
      wait "${pids[@]}"

      echo "모든 롤아웃 완료"

3. Slack Message Update

너무 많은 메세지가 쌓이면서 메세지를 뭉쳐야할 필요가 생김. 그래서 기존 글을 업데이트하거나 댓글에 부가정보를 달아야할 때가 있음. 이럴 때 사용할 수 있는 스크립트를 만들어봄.

#!/bin/bash

# 매개변수 확인
if [ $# -lt 3 ]; then
  echo "Usage: $0 [-u] <token> <new_message> <channel>"
  exit 1
fi

# 옵션 파싱
silent_mode=false
if [ "$1" == "-u" ]; then
  silent_mode=true
  shift
fi

# 매개변수 읽기
token="$1"                      # Slack App 토큰 (xoxb- 또는 xoxp-로 시작)
new_message="$2"                # 새 메시지
channel="$3"                    # 채널 ID 또는 채널 이름
timestamp_file=".slack_last_ts" # 로컬 timestamp 저장 파일

# Slack 메시지 업데이트 함수 (attachments 대체)
update_message_with_attachments() {
  local ts="$1"
  local msg="$2"

  # 새로운 attachment 생성
  new_attachments="[
    {
      \"color\": \"#3bb143\",
      \"text\": \"$msg\"
    }
  ]"

  # 메시지 업데이트 요청
  curl -s -X POST -H "Authorization: Bearer $token" -H 'Content-type: application/json' \
    --data "{
      \"channel\": \"$channel\",
      \"ts\": \"$ts\",
      \"attachments\": $new_attachments
    }" \
    https://slack.com/api/chat.update | jq .
}

# 댓글로 메시지 추가 함수
add_comment() {
  local ts="$1"
  local msg="$2"

  # 댓글 추가 요청
  response=$(curl -s -X POST -H "Authorization: Bearer $token" -H 'Content-type: application/json' \
    --data "{
      \"channel\": \"$channel\",
      \"text\": \"$msg\",
      \"thread_ts\": \"$ts\"
    }" \
    https://slack.com/api/chat.postMessage)

  # 응답 디버깅
  echo "$response" | jq .
}

# 새 메시지 전송 함수
send_message() {
  local msg="$1"
  response=$(curl -s -X POST -H "Authorization: Bearer $token" -H 'Content-type: application/json' \
    --data "{
      \"channel\": \"$channel\",
      \"text\": \"$msg\"
    }" \
    https://slack.com/api/chat.postMessage)

  # 메시지 전송 후 timestamp 추출
  local ts
  ts=$(echo "$response" | jq -r '.ts')
  if [[ "$ts" != "null" ]]; then
    echo "$ts" > "$timestamp_file"
    echo "Message sent with ts: $ts"
  else
    echo "Failed to send message. Response: $response"
  fi
}

if [ -f "$timestamp_file" ]; then
  ts=$(cat "$timestamp_file")
  echo "Found existing timestamp: $ts"

  if [ -z "$ts" ]; then
    echo "Timestamp is empty. Sending new message..."
    send_message "$new_message"
  else
    if $silent_mode; then
      echo "Replacing attachments for ts: $ts"
      update_message_with_attachments "$ts" "$new_message"
    else
      echo "Adding comment to existing message with ts: $ts"
      add_comment "$ts" "$new_message"
    fi
  fi
else
  echo "timestamp file not found. Sending new message..."
  send_message "$new_message"
fi

위의 3가지 + a가 자동화되서 아래와 같은 결과를 알림으로 받을 수 있음.

img_5.png

Appendix

  • shell script multiple background process waiting

    bash 특정버전 이후 부터는 wait 명령어로 여러개의 백그라운드 프로세스를 기다릴 수 있음. 이전 버전에서는 wait 명령어가 하나의 pid 만을 기다렸음.

  • bash 의 while 은 서브쉘 실행해서 다른 프로세스임. 그래서 메모리를 카피해서 일단 가져오지만(copy-on-write) 부모쉘 메모리에 저장된 변수에 값을 변경하거나 추가할 수 없고 카피된 값을 읽을수만 있음. 그래서 for loop 로 돌려야함