본문으로 건너뛰기

Azure VM 배포

Azure VM(B2s, Ubuntu 22.04 amd64)에 quant-ai를 무중단 배포하기 위한 절차입니다. Apple Silicon 개발 머신에서 amd64 이미지를 크로스 빌드하고, ACR에 푸시한 뒤, scripts/deploy_azure.sh가 SSH로 VM에 적용합니다.

사전 요구 사항

  • Azure VM (Standard B2s, Ubuntu 22.04, 퍼블릭 IP 보유)
  • Azure Container Registry (quantaiacr.azurecr.io)
  • 로컬 개발 머신에 다음이 설치됨
    • az CLI (az login 완료)
    • docker buildx (Docker Desktop 4.25+에 포함)
    • SSH 키 (~/.ssh/id_*가 VM의 azureuser에 등록됨)
  • VM에 다음이 설치됨
    • Docker Engine 24+
    • git, curl, cron
Azure 리소스 태그 정책

모든 Azure 리소스(VM, ACR, NSG)는 Owner, Department, CostCenter, Environment 4개 태그를 필수로 갖습니다. 태그 누락 시 정책 위반으로 배포가 거절됩니다.

1. 환경 변수 설정

로컬 셸에 다음을 export 합니다 (필요 시 ~/.zshrc 등에 영구 반영).

export VM_IP="20.196.217.226" # 실제 VM IP로 교체
export VM_USER="azureuser"
export ACR_NAME="quantaiacr"
export ACR_LOGIN_SERVER="${ACR_NAME}.azurecr.io"

2. VM 초기 셋업 (1회)

ssh ${VM_USER}@${VM_IP} '
set -e
sudo apt-get update && sudo apt-get install -y docker.io docker-compose-plugin git curl
sudo usermod -aG docker $USER
mkdir -p ~/quantai
'

# .env / docker-compose.prod.yml 송부
scp .env ${VM_USER}@${VM_IP}:~/quantai/.env
scp docker-compose.prod.yml ${VM_USER}@${VM_IP}:~/quantai/

ssh ${VM_USER}@${VM_IP} '
chmod 600 ~/quantai/.env
'

VM의 .env에는 로컬과 다른 값을 둡니다.

변수VM 값비고
DB_PASSWORD강한 임의 문자열docker-compose.prod.yml:?Set DB_PASSWORD로 강제
AUTH_SECRET_KEY새 임의 문자열 (로컬과 다름)JWT 서명
ENCRYPTION_SALT새 임의 문자열Fernet 파생
ALLOW_LIVE0 (초반), 1 (라이브 활성 시)FEATURE_EQUITY_LIVE의 킬 스위치
IMAGE_TAG(배포 스크립트가 자동 갱신)git short sha
ALLOW_LIVE 이중 잠금

docker-compose.prod.ymlapp-env 앵커:

FEATURE_EQUITY_LIVE: ${ALLOW_LIVE:+${FEATURE_EQUITY_LIVE:-false}}

ALLOW_LIVE가 비어 있으면 FEATURE_EQUITY_LIVE도 빈값(=false)으로 강제됩니다. 페이퍼 .env를 실수로 VM에 복사해도 라이브가 켜지지 않게 하기 위함입니다.

3. ACR 연결

# 로컬에서 ACR 로그인 (deploy 스크립트가 매번 자동 실행하지만, 첫 회는 수동 권장)
az acr login --name "${ACR_NAME}"

# VM에서도 ACR pull 권한 필요
ssh ${VM_USER}@${VM_IP} "
sudo az acr login --name ${ACR_NAME}
"

장기적으로는 VM에 managed identity를 붙이고 ACR AcrPull 역할을 할당합니다.

4. 첫 배포

scripts/deploy_azure.sh가 다음을 자동화합니다.

  1. docker buildx build --platform linux/amd64 --push (api + web 2개 이미지)
  2. VM의 ~/quantai/.deploy_envIMAGE_TAG 기록 (이전 태그는 .deploy_env.previous로 백업)
  3. docker-compose.prod.yml + scripts/rolling_restart.sh + infra/healthcheck.sh 동기화 (rsync/scp)
  4. VM에서 docker compose pullalembic upgrade headbash scripts/rolling_restart.sh
  5. http://${VM_IP}/health로 스모크 테스트
  6. 실패 시 자동 롤백 (--rollback)
# 로컬 quant-ai 레포 루트에서
bash scripts/deploy_azure.sh

빌드까지 평균 812분, 배포는 추가 12분입니다.

명시적 태그를 쓰고 싶다면:

bash scripts/deploy_azure.sh --tag v2026.04.26

이미 푸시한 이미지로 재배포만 하려면:

bash scripts/deploy_azure.sh --skip-build

이전 태그로 즉시 롤백:

bash scripts/deploy_azure.sh --rollback

5. 검증

# 헬스 200
curl -fsS "http://${VM_IP}/health"

# 웹 200/304
curl -I "http://${VM_IP}/"

# 컨테이너 상태
ssh ${VM_USER}@${VM_IP} 'cd ~/quantai && sudo docker compose -f docker-compose.prod.yml ps'

# 최근 50행 로그
ssh ${VM_USER}@${VM_IP} 'cd ~/quantai && sudo docker compose -f docker-compose.prod.yml logs --tail=50 api'

자동 일일 헬스체크는 헬스체크 cron에서 설정합니다.

6. 무중단 배포 (rolling restart)

scripts/rolling_restart.sh가 내부적으로 다음 순서로 재시작합니다.

순서컨테이너graceful 타임아웃의도
1position-reconciler30s단일 replica, 5분 누락 허용
2analysis-worker60slease 반환 시간 확보
3api(force-recreate)/health 200을 30회 폴링
4web(recreate)nginx 재기동

api가 30회 폴링 안에 healthy가 아니면 스크립트가 비제로 종료하므로 deploy_azure.sh는 자동으로 --rollback을 호출합니다.

7. 자주 쓰는 운영 명령

# Compose 명령을 VM에서 실행
ssh ${VM_USER}@${VM_IP} 'cd ~/quantai && sudo -E docker compose -f docker-compose.prod.yml ps'

# 로그 실시간
ssh ${VM_USER}@${VM_IP} 'cd ~/quantai && sudo -E docker compose -f docker-compose.prod.yml logs -f --tail=100 api'

# alembic 현재 revision
ssh ${VM_USER}@${VM_IP} 'cd ~/quantai && sudo -E docker compose -f docker-compose.prod.yml exec -T api alembic current'

# emergency stop (모든 사용자 라이브 차단)
ssh ${VM_USER}@${VM_IP} 'cd ~/quantai && sed -i "s/^ALLOW_LIVE=.*/ALLOW_LIVE=0/" .env && sudo -E docker compose -f docker-compose.prod.yml restart api'

자세한 절차는 비상 정지 참조.

트러블슈팅

증상원인 / 조치
buildx 단계에서 exec format error--platform linux/amd64가 없음 — scripts/deploy_azure.sh 사용 권장
ACR push가 401az acr login 토큰 만료. 로컬에서 다시 로그인
VM에서 pull이 401VM의 sudo az acr login 실행 또는 managed identity 미할당
--rollback인데 no previous tag recorded.deploy_env.previous 부재 (첫 배포 또는 수동 정리됨). 이전 태그를 명시적으로 --tag로 재배포
/health 200인데 web 503nginx upstream(api) 부팅 직전. 30~60초 후 재시도. 그래도 503이면 DB 마이그 실패

관련 페이지