created at 2025-01-18
Table of contents
- 1. 빌드 & 모니터링 자동화
- 2. Slack List Notification(upload to actions marketplace)
- 3. K8S 롤아웃 자동 트래킹 (image pullback off 에러, 런타임 시 발생한 에러들 알 수 있기 위함)
- 3. Slack Message Update
- 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)
뭔가 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 에러, 런타임 시 발생한 에러들 알 수 있기 위함)
원래는 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가 자동화되서 아래와 같은 결과를 알림으로 받을 수 있음.
Appendix
- shell script multiple background process waiting
bash 특정버전 이후 부터는 wait 명령어로 여러개의 백그라운드 프로세스를 기다릴 수 있음. 이전 버전에서는 wait 명령어가 하나의 pid 만을 기다렸음.
- bash 의 while 은 서브쉘 실행해서 다른 프로세스임. 그래서 메모리를 카피해서 일단 가져오지만(copy-on-write) 부모쉘 메모리에 저장된 변수에 값을 변경하거나 추가할 수 없고 카피된 값을 읽을수만 있음. 그래서 for loop 로 돌려야함