refactor docs into technical specs
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
# Deployment and Operations
|
||||
|
||||
- Related REQ: N/A
|
||||
|
||||
## 목표
|
||||
PortfolioHub를 Linux 환경에서 안정적으로 배포하고 HTTPS 종단, 프로세스 복구, 기본 점검 경로를 표준화한다.
|
||||
|
||||
## 사전 조건
|
||||
|
||||
- public IP를 가진 Linux/Ubuntu 서버
|
||||
- 해당 IP를 가리키는 도메인 DNS `A` record
|
||||
- 방화벽에서 `80`, `443` 포트 개방
|
||||
|
||||
## 권장 배포 토폴로지
|
||||
- App: `uvicorn app.main:app`
|
||||
- Reverse proxy/TLS: Caddy
|
||||
- Process manager: systemd
|
||||
- 선택: Docker Compose + Caddy sidecar
|
||||
|
||||
## Linux Direct Run 기준
|
||||
1. Python 가상환경 생성 후 패키지를 설치한다.
|
||||
2. 환경 변수 또는 `.env`를 구성한다.
|
||||
3. `uvicorn app.main:app --host 127.0.0.1 --port 8000 --workers 2`를 실행한다.
|
||||
4. `GET /health`를 확인한다.
|
||||
|
||||
## Caddy 설치와 구성
|
||||
|
||||
Ubuntu/Debian 설치 예시:
|
||||
|
||||
```bash
|
||||
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
|
||||
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
|
||||
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
||||
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
|
||||
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
|
||||
sudo apt update
|
||||
sudo apt install caddy
|
||||
```
|
||||
|
||||
설치 검증:
|
||||
|
||||
```bash
|
||||
caddy version
|
||||
```
|
||||
|
||||
기본 Caddyfile:
|
||||
|
||||
```text
|
||||
your-domain.com {
|
||||
reverse_proxy localhost:8000
|
||||
}
|
||||
```
|
||||
|
||||
동작 기준:
|
||||
|
||||
- TLS 인증서 자동 발급/갱신
|
||||
- `80`에서 `443`으로 HTTP redirect
|
||||
- 외부 요청을 내부 `uvicorn` 프로세스(`127.0.0.1:8000`)로 전달
|
||||
|
||||
적용 후 reload:
|
||||
|
||||
```bash
|
||||
sudo systemctl reload caddy
|
||||
```
|
||||
|
||||
## systemd 운영 기준
|
||||
- 서비스 계정 권한 최소화
|
||||
- `Restart=on-failure`
|
||||
- 로그 수집 경로(journalctl 또는 외부 수집기) 확보
|
||||
|
||||
예시 unit 파일:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=PortfolioHub API
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=www-data
|
||||
WorkingDirectory=/opt/portfoliohub
|
||||
EnvironmentFile=/opt/portfoliohub/.env
|
||||
ExecStart=/opt/portfoliohub/.venv/bin/uvicorn app.main:app \
|
||||
--host 127.0.0.1 --port 8000 --workers 2
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
등록/기동:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable portfoliohub
|
||||
sudo systemctl start portfoliohub
|
||||
```
|
||||
|
||||
## HTTPS/Caddy 운영 기준
|
||||
- 도메인 DNS가 서버 IP를 가리켜야 한다.
|
||||
- 포트 `80/443`을 개방한다.
|
||||
- Caddyfile에서 앱을 `reverse_proxy`로 연결한다.
|
||||
- 브라우저 기반 frontend가 있으면 `PORTFOLIOHUB_ALLOWED_ORIGINS`에 정확한 HTTPS origin을 지정한다.
|
||||
|
||||
예시:
|
||||
|
||||
```bash
|
||||
PORTFOLIOHUB_ALLOWED_ORIGINS=https://app.example.com,https://www.example.com
|
||||
```
|
||||
|
||||
## Docker Compose 운영 기준
|
||||
- 앱 컨테이너는 내부 포트만 expose하고 외부 종단은 Caddy가 담당한다.
|
||||
- `caddy_data`, `caddy_config` 볼륨을 유지해 인증서 상태를 보존한다.
|
||||
- 배포 후 `docker compose ps`, `curl /health`로 기본 상태를 확인한다.
|
||||
|
||||
예시 compose:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
expose:
|
||||
- "8000"
|
||||
environment:
|
||||
- PORTFOLIOHUB_ALLOWED_ORIGINS=https://your-domain.com
|
||||
restart: unless-stopped
|
||||
|
||||
caddy:
|
||||
image: caddy:2-alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
depends_on:
|
||||
- app
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
```
|
||||
|
||||
compose 네트워크 안에서는 `reverse_proxy app:8000`을 사용한다.
|
||||
|
||||
기동:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## 방화벽 설정
|
||||
|
||||
UFW:
|
||||
|
||||
```bash
|
||||
sudo ufw allow 80/tcp
|
||||
sudo ufw allow 443/tcp
|
||||
sudo ufw reload
|
||||
```
|
||||
|
||||
firewalld:
|
||||
|
||||
```bash
|
||||
sudo firewall-cmd --permanent --add-service=http
|
||||
sudo firewall-cmd --permanent --add-service=https
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
## 배포 검증
|
||||
|
||||
HTTPS health check:
|
||||
|
||||
```bash
|
||||
curl https://your-domain.com/health
|
||||
```
|
||||
|
||||
운영 상태 확인:
|
||||
|
||||
```bash
|
||||
sudo systemctl status caddy
|
||||
sudo journalctl -u caddy -f
|
||||
```
|
||||
|
||||
## Validation Notes
|
||||
- HTTPS 엔드포인트에서 `/health`, `/docs` 접근이 가능해야 한다.
|
||||
- DB 사용 배포에서는 마이그레이션 적용 후 앱을 기동한다.
|
||||
- CORS 오리진 설정과 실제 프론트엔드 도메인이 일치해야 한다.
|
||||
|
||||
## Open Implementation Points
|
||||
- blue/green 또는 rolling update 같은 무중단 배포 전략 도입 여부를 확정한다.
|
||||
- Loki/metrics 통합 운영 절차를 별도 런북으로 분리할지 결정한다.
|
||||
Reference in New Issue
Block a user