docs: ops-manual 배포 가이드 현행화

- 05-deployment.md: Jenkinsfile 코드블록 전체 현행화
  - React/API/MNG: slackSend + tokenCredentialId 추가
  - API/MNG: mkdir-p bootstrap/cache, storage/framework 추가
  - MNG: npm install --production=false → --prefer-offline
  - 수동배포 섹션: mkdir-p 추가, 단계 번호 재정렬
  - 빌드 실패 트러블슈팅: Laravel 디렉토리 누락 항목 추가
- 07-monitoring.md: Contact Point TODO → 실제 설정 완료 내용 반영

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 23:53:56 +09:00
parent 48ef98e20a
commit 4610ae128b
2 changed files with 60 additions and 19 deletions

View File

@@ -206,7 +206,11 @@ pipeline {
stages {
stage('Checkout') {
steps { checkout scm }
steps {
slackSend channel: '#product_infra', color: '#439FE0', tokenCredentialId: 'slack-token',
message: "🚀 *react* 빌드 시작 (`${env.BRANCH_NAME}`)\n<${env.BUILD_URL}|빌드 #${env.BUILD_NUMBER}>"
checkout scm
}
}
stage('Prepare Env') {
@@ -312,8 +316,14 @@ pipeline {
}
post {
success { echo '✅ react 배포 완료 (' + env.BRANCH_NAME + ')' }
failure { echo '❌ react 배포 실패 (' + env.BRANCH_NAME + ')' }
success {
slackSend channel: '#product_infra', color: 'good', tokenCredentialId: 'slack-token',
message: "✅ *react* 배포 성공 (`${env.BRANCH_NAME}`)\n<${env.BUILD_URL}|빌드 #${env.BUILD_NUMBER}>"
}
failure {
slackSend channel: '#product_infra', color: 'danger', tokenCredentialId: 'slack-token',
message: "❌ *react* 배포 실패 (`${env.BRANCH_NAME}`)\n<${env.BUILD_URL}|빌드 #${env.BUILD_NUMBER}>"
}
}
}
```
@@ -369,7 +379,11 @@ pipeline {
stages {
stage('Checkout') {
steps { checkout scm }
steps {
slackSend channel: '#product_infra', color: '#439FE0', tokenCredentialId: 'slack-token',
message: "🚀 *api* 빌드 시작 (`${env.BRANCH_NAME}`)\n<${env.BUILD_URL}|빌드 #${env.BUILD_NUMBER}>"
checkout scm
}
}
// ── main → 운영서버 Stage 배포 ──
@@ -386,6 +400,7 @@ pipeline {
. ${DEPLOY_USER}@211.117.60.189:/home/webservice/api-stage/releases/${RELEASE_ID}/
ssh ${DEPLOY_USER}@211.117.60.189 '
cd /home/webservice/api-stage/releases/${RELEASE_ID} &&
mkdir -p bootstrap/cache storage/framework/{views,cache/data,sessions} storage/logs &&
ln -sfn /home/webservice/api-stage/shared/.env .env &&
ln -sfn /home/webservice/api-stage/shared/storage/app storage/app &&
composer install --no-dev --optimize-autoloader --no-interaction &&
@@ -427,6 +442,7 @@ pipeline {
. ${DEPLOY_USER}@211.117.60.189:/home/webservice/api/releases/${RELEASE_ID}/
ssh ${DEPLOY_USER}@211.117.60.189 '
cd /home/webservice/api/releases/${RELEASE_ID} &&
mkdir -p bootstrap/cache storage/framework/{views,cache/data,sessions} storage/logs &&
ln -sfn /home/webservice/api/shared/.env .env &&
ln -sfn /home/webservice/api/shared/storage/app storage/app &&
composer install --no-dev --optimize-autoloader --no-interaction &&
@@ -448,9 +464,13 @@ pipeline {
}
post {
success { echo "✅ api 배포 완료 (${env.BRANCH_NAME})" }
success {
slackSend channel: '#product_infra', color: 'good', tokenCredentialId: 'slack-token',
message: "✅ *api* 배포 성공 (`${env.BRANCH_NAME}`)\n<${env.BUILD_URL}|빌드 #${env.BUILD_NUMBER}>"
}
failure {
echo "❌ api 배포 실패 (${env.BRANCH_NAME})"
slackSend channel: '#product_infra', color: 'danger', tokenCredentialId: 'slack-token',
message: "❌ *api* 배포 실패 (`${env.BRANCH_NAME}`)\n<${env.BUILD_URL}|빌드 #${env.BUILD_NUMBER}>"
script {
if (env.BRANCH_NAME == 'main') {
sshagent(credentials: ['deploy-ssh-key']) {
@@ -490,26 +510,29 @@ git clone --depth 1 --branch main https://git.sam.it.kr/SamProject/sam-api.git $
ln -sfn /home/webservice/api/shared/storage /home/webservice/api/releases/$RELEASE_ID/storage
ln -sfn /home/webservice/api/shared/.env /home/webservice/api/releases/$RELEASE_ID/.env
# 3. 의존성 설치
# 3. 필수 디렉토리 생성 (.gitignore에 의해 누락)
cd /home/webservice/api/releases/$RELEASE_ID
mkdir -p bootstrap/cache storage/framework/{views,cache/data,sessions} storage/logs
# 4. 의존성 설치
composer install --no-dev --optimize-autoloader --no-interaction
# 4. 캐시 생성
# 5. 캐시 생성
php artisan config:cache
php artisan route:cache
php artisan view:cache
# 5. 마이그레이션 (필요시)
# 6. 마이그레이션 (필요시)
php artisan migrate --force
# 6. 심링크 전환 (이 시점에 배포 적용)
# 7. 심링크 전환 (이 시점에 배포 적용)
ln -sfn /home/webservice/api/releases/$RELEASE_ID /home/webservice/api/current
# 7. 서비스 리로드
# 8. 서비스 리로드
sudo systemctl reload php8.4-fpm
sudo supervisorctl restart sam-queue-worker:*
# 8. 오래된 릴리즈 정리 (최근 5개만 유지)
# 9. 오래된 릴리즈 정리 (최근 5개만 유지)
cd /home/webservice/api/releases
ls -1dt */ | tail -n +6 | xargs rm -rf 2>/dev/null || true
```
@@ -527,6 +550,7 @@ ln -sfn /home/webservice/api-stage/shared/storage /home/webservice/api-stage/rel
ln -sfn /home/webservice/api-stage/shared/.env /home/webservice/api-stage/releases/$RELEASE_ID/.env
cd /home/webservice/api-stage/releases/$RELEASE_ID
mkdir -p bootstrap/cache storage/framework/{views,cache/data,sessions} storage/logs
composer install --no-dev --optimize-autoloader --no-interaction
php artisan config:cache
php artisan route:cache
@@ -560,7 +584,11 @@ pipeline {
stages {
stage('Checkout') {
steps { checkout scm }
steps {
slackSend channel: '#product_infra', color: '#439FE0', tokenCredentialId: 'slack-token',
message: "🚀 *mng* 빌드 시작 (`${env.BRANCH_NAME}`)\n<${env.BUILD_URL}|빌드 #${env.BUILD_NUMBER}>"
checkout scm
}
}
// ── main → 운영서버 Production ──
@@ -578,10 +606,11 @@ pipeline {
. ${DEPLOY_USER}@211.117.60.189:/home/webservice/mng/releases/${RELEASE_ID}/
ssh ${DEPLOY_USER}@211.117.60.189 '
cd /home/webservice/mng/releases/${RELEASE_ID} &&
mkdir -p bootstrap/cache storage/framework/{views,cache/data,sessions} storage/logs &&
ln -sfn /home/webservice/mng/shared/.env .env &&
ln -sfn /home/webservice/mng/shared/storage/app storage/app &&
composer install --no-dev --optimize-autoloader --no-interaction &&
npm install --production=false &&
npm install --prefer-offline &&
npm run build &&
php artisan config:cache &&
php artisan route:cache &&
@@ -600,9 +629,13 @@ pipeline {
}
post {
success { echo "✅ mng 배포 완료 (${env.BRANCH_NAME})" }
success {
slackSend channel: '#product_infra', color: 'good', tokenCredentialId: 'slack-token',
message: "✅ *mng* 배포 성공 (`${env.BRANCH_NAME}`)\n<${env.BUILD_URL}|빌드 #${env.BUILD_NUMBER}>"
}
failure {
echo "❌ mng 배포 실패 (${env.BRANCH_NAME})"
slackSend channel: '#product_infra', color: 'danger', tokenCredentialId: 'slack-token',
message: "❌ *mng* 배포 실패 (`${env.BRANCH_NAME}`)\n<${env.BUILD_URL}|빌드 #${env.BUILD_NUMBER}>"
script {
if (env.BRANCH_NAME == 'main') {
sshagent(credentials: ['deploy-ssh-key']) {
@@ -634,10 +667,11 @@ ln -sfn /home/webservice/mng/shared/storage /home/webservice/mng/releases/$RELEA
ln -sfn /home/webservice/mng/shared/.env /home/webservice/mng/releases/$RELEASE_ID/.env
cd /home/webservice/mng/releases/$RELEASE_ID
mkdir -p bootstrap/cache storage/framework/{views,cache/data,sessions} storage/logs
composer install --no-dev --optimize-autoloader --no-interaction
# Vite 빌드 (Blade + Tailwind)
npm install --production=false
npm install --prefer-offline
npm run build
php artisan config:cache
@@ -807,6 +841,7 @@ ssh sam-prod "
ln -sfn /home/webservice/api/shared/storage /home/webservice/api/releases/${RELEASE_ID}/storage &&
ln -sfn /home/webservice/api/shared/.env /home/webservice/api/releases/${RELEASE_ID}/.env &&
cd /home/webservice/api/releases/${RELEASE_ID} &&
mkdir -p bootstrap/cache storage/framework/{views,cache/data,sessions} storage/logs &&
composer install --no-dev --optimize-autoloader --no-interaction &&
php artisan config:cache &&
php artisan route:cache &&
@@ -874,4 +909,10 @@ ls -la /var/lib/jenkins/workspace/
2. npm run build 실패 -- TypeScript 오류, 환경변수 누락
3. rsync 실패 -- SSH 키 문제, 디스크 공간 부족
4. composer install 실패 -- 네트워크, PHP 확장 누락
5. SSH 연결 실패 -- known_hosts 변경, 키 만료
5. SSH 연결 실패 -- known_hosts 변경, 키 만료
6. Laravel `package:discover` 실패 -- `bootstrap/cache/` 디렉토리 누락 (`.gitignore`에 포함)
7. Blade view 캐시 실패 -- `storage/framework/views/` 디렉토리 누락
8. `Target class [request] does not exist` -- CLI 컨텍스트에서 `request()` 호출 (AppServiceProvider 확인)
> **Laravel 배포 필수:** `mkdir -p bootstrap/cache storage/framework/{views,cache/data,sessions} storage/logs`를
> `composer install` 전에 실행해야 함. `.gitignore`가 이 디렉토리들을 제외하므로 rsync/git clone 후 생성 필요.

View File

@@ -167,7 +167,7 @@ node_filefd_allocated
**알림 채널:** Grafana > Alerting > Contact points 에서 이메일, Slack 등 설정
> **TODO:** Contact Point에 실제 이메일 주소 또는 Slack Webhook 설정 필요 (현재 기본 email placeholder)
**현재 설정:** SAM Slack Contact Point (Incoming Webhook) 연결 완료. Notification Policy에서 SAM Alerts 폴더의 알림이 Slack `#product_infra` 채널로 전송됨.
---