1. Slack Incoming Webhook 생성
1.1. Incoming Webhook이란
Slack에 Slack이 정한 포맷에 일치하는 데이터를 보내주면, 지정된 채널에 메시지를 보내주는 기능.
1.2. Webhook URL 생성
1) https://api.slack.com 접속 > Your apps > Create your first app
Create New App을 눌러 App을 생성한다.
From scratch 를 누른다.
App Name과 알림을 적용할 워크스페이스를 선택하여 Create App 을 한다.
App이 생성되었으면, 좌측 탭에 Incoming Webhooks 을 누른 후 토글을 On으로 변경한다.
그리고 맨 아래 Add New Webhook 버튼을 누른다.
마지막으로 적용할 채널을 선택하고 허용을 누른다.
정상적으로 동작하였으면 아래쪽에 Webhook URL이 생성된다.
적용된 채널에서도 슬랙에 알림이 뜨는데, 어떤 App이 추가되었는지 알려준다.
2. Github Actions Secrets 추가
프로젝트 레포지토리 - Settings - Secrets and variables - Actions 로 이동한다.
Name을 설정하고, 복사해둔 Webhook URL을 Secret 란에 붙여넣는다.
3. Github Actions deploy.yml 수정
name: 🚀 Deploy to NAS
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
workflow_dispatch:
env:
NODE_VERSION: '20'
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- name: 📥 체크아웃
uses: actions/checkout@v4
- name: 📦 Node.js 설정
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 📦 pnpm 설치 (버전 통일)
uses: pnpm/action-setup@v2
with:
version: latest
- name: 📦 의존성 캐시
uses: actions/cache@v3
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: 🔍 pnpm 및 lock 파일 정보 확인
run: |
echo "=== 환경 정보 ==="
echo "Node.js 버전: $(node --version)"
echo "pnpm 버전: $(pnpm --version)"
echo "현재 디렉토리: $(pwd)"
echo "=== lock 파일 상태 ==="
if [ -f pnpm-lock.yaml ]; then
echo "✅ pnpm-lock.yaml 존재"
echo "파일 크기: $(wc -c < pnpm-lock.yaml) bytes"
echo "첫 5줄:"
head -5 pnpm-lock.yaml
else
echo "❌ pnpm-lock.yaml 없음"
fi
echo "=== package.json 확인 ==="
if [ -f package.json ]; then
echo "✅ package.json 존재"
else
echo "❌ package.json 없음"
fi
- name: 📦 의존성 설치
run: |
echo "=== 의존성 설치 시작 ==="
if [ -f pnpm-lock.yaml ]; then
echo "📦 pnpm-lock.yaml 발견 - lock 파일 검증 중..."
if pnpm install --frozen-lockfile --dry-run; then
echo "✅ lock 파일 호환됨 - frozen-lockfile 모드 사용"
pnpm install --frozen-lockfile
else
echo "⚠️ lock 파일 비호환 - lock 파일 재생성"
rm pnpm-lock.yaml
pnpm install
echo "📝 새로운 pnpm-lock.yaml 생성됨"
fi
else
echo "⚠️ pnpm-lock.yaml 없음 - 새로 생성"
pnpm install
fi
- name: 🔍 린트 검사
run: pnpm run lint
- name: 🧪 테스트 실행
run: pnpm run test
- name: 🏗️ 빌드 테스트
run: pnpm run build
# 테스트 실패 시 즉시 알림
- name: 📢 테스트 실패 알림
if: failure()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
"text": "🚨 **테스트가 실패했습니다!**",
"attachments": [{
"color": "danger",
"fields": [
{
"title": "Repository",
"value": "${{ github.repository }}",
"short": true
},
{
"title": "Branch",
"value": "${{ github.ref_name }}",
"short": true
},
{
"title": "Commit",
"value": "${{ github.sha }}",
"short": true
},
{
"title": "Author",
"value": "${{ github.actor }}",
"short": true
}
],
"text": "코드 품질 검사 또는 테스트에서 오류가 발생했습니다.\n\n**액션 링크**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}]
}' \
"${{ secrets.SLACK_WEBHOOK_URL }}"
deploy:
needs: lint-and-test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: 📥 체크아웃
uses: actions/checkout@v4
# 배포 시작 알림
- name: 📢 배포 시작 알림
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
"text": "🚀 **배포 시작**",
"attachments": [{
"color": "#2eb886",
"pretext": "NAS 서버 배포가 시작되었습니다",
"fields": [
{
"title": "Repository",
"value": "<${{ github.server_url }}/${{ github.repository }}|${{ github.repository }}>",
"short": true
},
{
"title": "Branch",
"value": "`${{ github.ref_name }}`",
"short": true
},
{
"title": "Commit",
"value": "<${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|`${{ github.sha }}`>",
"short": true
},
{
"title": "Author",
"value": "${{ github.actor }}",
"short": true
},
{
"title": "DDNS Host",
"value": "`${{ secrets.NAS_DDNS }}`",
"short": true
},
{
"title": "Workflow",
"value": "${{ github.workflow }}",
"short": true
}
],
"footer": "GitHub Actions CI/CD",
"footer_icon": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
}]
}' \
"${{ secrets.SLACK_WEBHOOK_URL }}"
- name: 🚀 NAS 서버 배포 및 검증 (DDNS)
id: deploy
uses: appleboy/ssh-action@v1.1.0
with:
host: ${{ secrets.NAS_DDNS }}
username: ${{ secrets.NAS_USERNAME }}
password: ${{ secrets.NAS_PASSWORD }}
port: ${{ secrets.NAS_PORT }}
command_timeout: 30m
script: |
echo "======================================"
echo "🚀 GitHub Actions 배포 시작 (DDNS)"
echo "======================================"
echo "📊 배포 정보:"
echo " - Repository: ${{ github.repository }}"
echo " - Branch: ${{ github.ref_name }}"
echo " - Commit: ${{ github.sha }}"
echo " - Actor: ${{ github.actor }}"
echo " - DDNS Host: ${{ secrets.NAS_DDNS }}"
echo " - Timestamp: $(date '+%Y-%m-%d %H:%M:%S')"
echo "======================================"
cd ${{ secrets.NAS_PROJECT_PATH }}
git log --oneline -3
echo ""
# deploy.sh 실행 (DDNS 호스트 전달)
./deploy.sh "${{ secrets.NAS_PASSWORD }}" "${{ secrets.NAS_DDNS }}"
DEPLOY_EXIT_CODE=$?
if [ $DEPLOY_EXIT_CODE -eq 0 ]; then
echo "======================================"
echo "✅ 배포 완료 - 추가 검증 수행"
echo "======================================"
# 내부에서 포트별 서비스 상태 확인
echo "🔍 포트별 서비스 상태 확인"
# API 서버 포트 확인
if netstat -tuln | grep ":3000 " > /dev/null; then
echo "✅ API 서버 포트 3000 활성화"
else
echo "❌ API 서버 포트 3000 비활성화"
exit 1
fi
# 문서 서버 포트 확인
if netstat -tuln | grep ":8080 " > /dev/null; then
echo "✅ 문서 서버 포트 8080 활성화"
else
echo "⚠️ 문서 서버 포트 8080 비활성화 (선택적)"
fi
# 다양한 엔드포인트 테스트 (내부 네트워크)
echo "🧪 API 엔드포인트 테스트 (내부)"
# 헬스체크 (내부)
if curl -f -s http://localhost:3000/health > /dev/null; then
echo "✅ 헬스체크 API 정상 (내부)"
else
echo "❌ 헬스체크 API 실패 (내부)"
exit 1
fi
# HTTPS 헬스체크 (역방향 프록시)
echo "🧪 HTTPS 엔드포인트 테스트 (역방향 프록시)"
if curl -k -f -s "https://${{ secrets.NAS_DDNS }}/health" > /dev/null; then
echo "✅ HTTPS 헬스체크 정상"
else
echo "⚠️ HTTPS 헬스체크 실패 (역방향 프록시 설정 확인 필요)"
fi
# Swagger UI 확인 (401도 정상으로 처리)
SWAGGER_STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" "https://${{ secrets.NAS_DDNS }}/api" 2>/dev/null)
if [ "$SWAGGER_STATUS" = "200" ] || [ "$SWAGGER_STATUS" = "401" ]; then
echo "✅ Swagger UI 접근 가능 (HTTP $SWAGGER_STATUS)"
else
echo "⚠️ Swagger UI 상태: HTTP $SWAGGER_STATUS"
fi
# GraphQL 확인 (400, 405도 정상으로 처리)
GRAPHQL_STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" "https://${{ secrets.NAS_DDNS }}/graphql" 2>/dev/null)
if [ "$GRAPHQL_STATUS" = "200" ] || [ "$GRAPHQL_STATUS" = "400" ] || [ "$GRAPHQL_STATUS" = "405" ]; then
echo "✅ GraphQL 엔드포인트 접근 가능 (HTTP $GRAPHQL_STATUS)"
else
echo "⚠️ GraphQL 상태: HTTP $GRAPHQL_STATUS"
fi
# Compodoc 문서 확인
DOCS_STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" "https://${{ secrets.NAS_DDNS }}:444/" 2>/dev/null)
if [ "$DOCS_STATUS" = "200" ]; then
echo "✅ Compodoc 문서 접근 가능 (HTTP $DOCS_STATUS)"
else
echo "⚠️ Compodoc 문서 상태: HTTP $DOCS_STATUS"
fi
# 컨테이너 상태 최종 확인
echo "📋 최종 컨테이너 상태"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep sns-dev
# 리소스 사용률 확인
echo "📊 시스템 리소스 사용률"
echo "메모리 사용률:"
free -h | head -2
echo "디스크 사용률:"
df -h | grep -E "(/$|/volume1)"
echo "======================================"
echo "✅ GitHub Actions 배포 및 검증 완료"
echo "🌐 HTTPS 서비스 접근:"
echo " 📡 API: https://${{ secrets.NAS_DDNS }}"
echo " 📋 Swagger: https://${{ secrets.NAS_DDNS }}/api"
echo " 🚀 GraphQL: https://${{ secrets.NAS_DDNS }}/graphql"
echo " 🔍 헬스체크: https://${{ secrets.NAS_DDNS }}/health"
echo " 📚 문서: https://${{ secrets.NAS_DDNS }}:444"
echo "💡 역방향 프록시를 통한 HTTPS 접근이 권장됩니다"
echo "======================================"
else
echo "❌ GitHub Actions 배포 실패 (Exit Code: $DEPLOY_EXIT_CODE)"
exit $DEPLOY_EXIT_CODE
fi
# 배포 성공 알림
- name: 📢 배포 성공 알림
if: success()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
"text": "✅ **배포 성공**",
"attachments": [{
"color": "good",
"pretext": "🎉 NAS 서버 배포가 성공적으로 완료되었습니다!",
"fields": [
{
"title": "Repository",
"value": "${{ github.repository }}",
"short": true
},
{
"title": "Branch",
"value": "`${{ github.ref_name }}`",
"short": true
},
{
"title": "Author",
"value": "${{ github.actor }}",
"short": true
},
{
"title": "DDNS Host",
"value": "`${{ secrets.NAS_DDNS }}`",
"short": true
}
],
"text": "🌐 **서비스 접근 링크**\n• 📡 API 서버: https://${{ secrets.NAS_DDNS }}\n• 📋 Swagger UI: https://${{ secrets.NAS_DDNS }}/api\n• 🚀 GraphQL: https://${{ secrets.NAS_DDNS }}/graphql\n• 🔍 헬스체크: https://${{ secrets.NAS_DDNS }}/health\n• 📚 문서: https://${{ secrets.NAS_DDNS }}:444\n\n✅ **검증 완료**\n• 컨테이너 상태: 정상\n• 내부 API: 정상\n• HTTPS 프록시: 정상\n• 데이터베이스: 연결됨\n\n**액션 로그**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}]
}' \
"${{ secrets.SLACK_WEBHOOK_URL }}"
# 배포 실패 알림
- name: 📢 배포 실패 알림
if: failure()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
"text": "❌ **배포 실패**",
"attachments": [{
"color": "danger",
"pretext": "🚨 NAS 서버 배포가 실패했습니다!",
"fields": [
{
"title": "Repository",
"value": "${{ github.repository }}",
"short": true
},
{
"title": "Branch",
"value": "`${{ github.ref_name }}`",
"short": true
},
{
"title": "Author",
"value": "${{ github.actor }}",
"short": true
},
{
"title": "DDNS Host",
"value": "`${{ secrets.NAS_DDNS }}`",
"short": true
}
],
"text": "🔧 **롤백 명령어**\n```\nssh ${{ secrets.NAS_USERNAME }}@${{ secrets.NAS_DDNS }}\ncd ${{ secrets.NAS_PROJECT_PATH }}\n./rollback.sh\n```\n\n📊 **문제 진단**\n1. **액션 로그 확인**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n2. **서버 로그 확인**: `docker logs sns-dev-app`\n3. **컨테이너 상태 확인**: `docker ps -a`\n4. **리소스 확인**: `df -h && free -h`\n\n🆘 **긴급 연락처**\n• 담당자: ${{ github.actor }}\n• 시간: $(date '+%Y-%m-%d %H:%M:%S UTC')"
}]
}' \
"${{ secrets.SLACK_WEBHOOK_URL }}"
# 배포 후 모니터링 및 헬스체크
post-deploy-monitoring:
needs: deploy
runs-on: ubuntu-latest
if: success()
steps:
- name: ⏳ 배포 안정화 대기
run: |
echo "🔄 서비스 완전 시작을 위해 60초 대기 중..."
sleep 60
- name: 🔍 서비스 헬스체크
id: healthcheck
run: |
echo "🔍 서비스 상태 점검 시작..."
# 헬스체크 수행
echo "📡 API 헬스체크 중..."
HEALTH_STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 10 "https://${{ secrets.NAS_DDNS }}/health" || echo "000")
echo "Health API Status: $HEALTH_STATUS"
echo "📋 Swagger API 체크 중..."
API_STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 10 "https://${{ secrets.NAS_DDNS }}/api" || echo "000")
echo "Swagger API Status: $API_STATUS"
echo "🚀 GraphQL 체크 중..."
GRAPHQL_STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 10 "https://${{ secrets.NAS_DDNS }}/graphql" || echo "000")
echo "GraphQL Status: $GRAPHQL_STATUS"
echo "📚 문서 서비스 체크 중..."
DOCS_STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 10 "https://${{ secrets.NAS_DDNS }}:444/" || echo "000")
echo "Docs Status: $DOCS_STATUS"
# GitHub Actions 출력으로 전달
echo "health_status=$HEALTH_STATUS" >> $GITHUB_OUTPUT
echo "api_status=$API_STATUS" >> $GITHUB_OUTPUT
echo "graphql_status=$GRAPHQL_STATUS" >> $GITHUB_OUTPUT
echo "docs_status=$DOCS_STATUS" >> $GITHUB_OUTPUT
# 전체 상태 판단
if [ "$HEALTH_STATUS" = "200" ]; then
echo "overall_status=healthy" >> $GITHUB_OUTPUT
echo "status_emoji=✅" >> $GITHUB_OUTPUT
echo "status_color=good" >> $GITHUB_OUTPUT
else
echo "overall_status=unhealthy" >> $GITHUB_OUTPUT
echo "status_emoji=⚠️" >> $GITHUB_OUTPUT
echo "status_color=danger" >> $GITHUB_OUTPUT
fi
# 각 서비스별 상태 텍스트 생성
HEALTH_TEXT=$([ "$HEALTH_STATUS" = "200" ] && echo "✅ 정상" || echo "❌ 이상")
API_TEXT=$([ "$API_STATUS" = "200" ] || [ "$API_STATUS" = "401" ] && echo "✅ 정상" || echo "❌ 이상")
GRAPHQL_TEXT=$([ "$GRAPHQL_STATUS" = "200" ] || [ "$GRAPHQL_STATUS" = "400" ] || [ "$GRAPHQL_STATUS" = "405" ] && echo "✅ 정상" || echo "❌ 이상")
DOCS_TEXT=$([ "$DOCS_STATUS" = "200" ] && echo "✅ 정상" || echo "❌ 이상")
echo "health_text=$HEALTH_TEXT" >> $GITHUB_OUTPUT
echo "api_text=$API_TEXT" >> $GITHUB_OUTPUT
echo "graphql_text=$GRAPHQL_TEXT" >> $GITHUB_OUTPUT
echo "docs_text=$DOCS_TEXT" >> $GITHUB_OUTPUT
- name: 📢 서비스 상태 알림
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
"text": "${{ steps.healthcheck.outputs.status_emoji }} **서비스 상태 점검 완료**",
"attachments": [{
"color": "${{ steps.healthcheck.outputs.status_color }}",
"pretext": "${{ steps.healthcheck.outputs.overall_status == 'healthy' && '모든 서비스가 정상적으로 운영 중입니다' || '일부 서비스에 문제가 감지되었습니다' }}",
"fields": [
{
"title": "🔍 Health Check API",
"value": "${{ steps.healthcheck.outputs.health_text }} (HTTP ${{ steps.healthcheck.outputs.health_status }})",
"short": true
},
{
"title": "📋 Swagger API",
"value": "${{ steps.healthcheck.outputs.api_text }} (HTTP ${{ steps.healthcheck.outputs.api_status }})",
"short": true
},
{
"title": "🚀 GraphQL",
"value": "${{ steps.healthcheck.outputs.graphql_text }} (HTTP ${{ steps.healthcheck.outputs.graphql_status }})",
"short": true
},
{
"title": "📚 Documentation",
"value": "${{ steps.healthcheck.outputs.docs_text }} (HTTP ${{ steps.healthcheck.outputs.docs_status }})",
"short": true
},
{
"title": "🌐 DDNS Host",
"value": "`${{ secrets.NAS_DDNS }}`",
"short": true
},
{
"title": "⏱️ 점검 시간",
"value": "방금 전",
"short": true
}
],
"footer": "Post-Deploy Health Check"
}]
}' \
"${{ secrets.SLACK_WEBHOOK_URL }}"
# 서비스 문제 감지 시 추가 알림
- name: 🚨 서비스 이상 긴급 알림
if: steps.healthcheck.outputs.overall_status == 'unhealthy'
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
"text": "🚨 **긴급: 서비스 상태 이상**",
"attachments": [{
"color": "danger",
"pretext": "배포는 성공했지만 서비스 상태에 문제가 있습니다!",
"fields": [
{
"title": "Repository",
"value": "${{ github.repository }}",
"short": true
},
{
"title": "DDNS Host",
"value": "`${{ secrets.NAS_DDNS }}`",
"short": true
},
{
"title": "Health Status",
"value": "HTTP ${{ steps.healthcheck.outputs.health_status }}",
"short": true
},
{
"title": "Detection Time",
"value": "방금 전",
"short": true
}
],
"text": "📊 **문제 상황**\n• Health Check: ${{ steps.healthcheck.outputs.health_text }} (HTTP ${{ steps.healthcheck.outputs.health_status }})\n• 메인 API가 응답하지 않고 있습니다\n\n🔧 **즉시 조치사항**\n1. 서버 상태 확인: `ssh ${{ secrets.NAS_USERNAME }}@${{ secrets.NAS_DDNS }}`\n2. 컨테이너 로그 확인: `docker logs sns-dev-app --tail=50`\n3. 컨테이너 재시작: `docker restart sns-dev-app`\n4. 필요시 롤백: `./rollback.sh`\n\n🆘 **담당자 즉시 확인 필요**\n\n**모니터링 링크**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}]
}' \
"${{ secrets.SLACK_WEBHOOK_URL }}"
deploy-summary:
needs: [lint-and-test, deploy, post-deploy-monitoring]
runs-on: ubuntu-latest
if: always()
steps:
- name: 📊 배포 결과 요약
run: |
echo "## 🚀 배포 결과 요약" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 항목 | 상태 |" >> $GITHUB_STEP_SUMMARY
echo "|------|------|" >> $GITHUB_STEP_SUMMARY
echo "| 🔍 코드 품질 검사 | ${{ needs.lint-and-test.result == 'success' && '✅ 성공' || '❌ 실패' }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🚀 NAS 배포 및 검증 | ${{ needs.deploy.result == 'success' && '✅ 성공' || '❌ 실패' }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🔍 배포 후 모니터링 | ${{ needs.post-deploy-monitoring.result == 'success' && '✅ 완료' || '❌ 실패' }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📋 배포 정보" >> $GITHUB_STEP_SUMMARY
echo "- **브랜치**: \`${{ github.ref_name }}\`" >> $GITHUB_STEP_SUMMARY
echo "- **커밋**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
echo "- **작성자**: ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
echo "- **DDNS 호스트**: \`${{ secrets.NAS_DDNS }}\`" >> $GITHUB_STEP_SUMMARY
echo "- **시간**: $(date '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.deploy.result }}" = "success" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🌐 서비스 접근 링크 (HTTPS 권장)" >> $GITHUB_STEP_SUMMARY
echo "#### 🔒 HTTPS 접근 (역방향 프록시)" >> $GITHUB_STEP_SUMMARY
echo "- 📡 **API 서버**: [https://${{ secrets.NAS_DDNS }}](https://${{ secrets.NAS_DDNS }})" >> $GITHUB_STEP_SUMMARY
echo "- 📋 **Swagger UI**: [https://${{ secrets.NAS_DDNS }}/api](https://${{ secrets.NAS_DDNS }}/api)" >> $GITHUB_STEP_SUMMARY
echo "- 🚀 **GraphQL**: [https://${{ secrets.NAS_DDNS }}/graphql](https://${{ secrets.NAS_DDNS }}/graphql)" >> $GITHUB_STEP_SUMMARY
echo "- 🔍 **헬스체크**: [https://${{ secrets.NAS_DDNS }}/health](https://${{ secrets.NAS_DDNS }}/health)" >> $GITHUB_STEP_SUMMARY
echo "- 📚 **문서**: [https://${{ secrets.NAS_DDNS }}:444](https://${{ secrets.NAS_DDNS }}:444)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 💡 참고사항" >> $GITHUB_STEP_SUMMARY
echo "- ✅ 내부 및 HTTPS 검증이 완료되었습니다" >> $GITHUB_STEP_SUMMARY
echo "- 🔒 HTTPS 접근이 권장됩니다 (SSL 인증서 적용)" >> $GITHUB_STEP_SUMMARY
echo "- 🌍 DDNS를 통한 안정적인 접근이 가능합니다" >> $GITHUB_STEP_SUMMARY
echo "- 📊 모니터링: \`docker exec sns-dev-monitor ./monitor.sh\`" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.deploy.result }}" = "failure" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ 배포 실패" >> $GITHUB_STEP_SUMMARY
echo "배포 중 오류가 발생했습니다. 로그를 확인하고 롤백을 고려하세요." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**롤백 명령어**:" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "ssh ${{ secrets.NAS_USERNAME }}@${{ secrets.NAS_DDNS }}" >> $GITHUB_STEP_SUMMARY
echo "cd ${{ secrets.NAS_PROJECT_PATH }}" >> $GITHUB_STEP_SUMMARY
echo "./rollback.sh" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
fi
# 최종 파이프라인 요약 알림
- name: 📢 파이프라인 완료 요약 알림
if: always()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
"text": "📊 **CI/CD 파이프라인 완료 요약**",
"attachments": [{
"color": "${{ needs.deploy.result == 'success' && 'good' || 'danger' }}",
"pretext": "${{ needs.deploy.result == 'success' && '✅ 전체 파이프라인 성공' || '❌ 파이프라인 실패' }}",
"fields": [
{
"title": "🔍 코드 품질 검사",
"value": "${{ needs.lint-and-test.result == 'success' && '✅ 성공' || '❌ 실패' }}",
"short": true
},
{
"title": "🚀 NAS 배포",
"value": "${{ needs.deploy.result == 'success' && '✅ 성공' || '❌ 실패' }}",
"short": true
},
{
"title": "🔍 배포 후 모니터링",
"value": "${{ needs.post-deploy-monitoring.result == 'success' && '✅ 완료' || needs.post-deploy-monitoring.result == 'skipped' && '⏭️ 생략됨' || '❌ 실패' }}",
"short": true
},
{
"title": "⏱️ 총 실행 시간",
"value": "약 5-10분",
"short": true
},
{
"title": "📝 커밋 메시지",
"value": "${{ github.event.head_commit.message || 'Manual trigger' }}",
"short": false
}
],
"footer": "GitHub Actions CI/CD Pipeline • ${{ github.repository }}"
}]
}' \
"${{ secrets.SLACK_WEBHOOK_URL }}"
배포 시작, 배포 성공, 실패, 요약 등의 알림을 보여준다.
4. 테스트 결과
정상적으로 작동하면 설정한 슬랙 채널에 위와 같이 알림이 발송된다.
'NestJS' 카테고리의 다른 글
Github Actions를 사용한 CI/CD - 백업 시스템 구축 (3) | 2025.07.04 |
---|---|
Github Actions를 사용한 CI/CD - 롤백, 모니터링, 로그 정리 (0) | 2025.07.02 |
Github Actions를 사용한 CI/CD 구축 (0) | 2025.06.30 |
시놀로지 나스 NestJS 개발서버 구축하기 - Docker Container (0) | 2025.06.19 |
[NestJS] winston 로그 구현하기 (1) | 2025.06.05 |