Django 블로그 백엔드. 기존 SQLite DB(mkblog-db.sqlite3)와 미디어(mkblog-media/)를 그대로 사용합니다.
| 항목 | 값 |
|---|---|
| DB 파일 | mkblog-db.sqlite3 (~995KB) |
| Post | 264건 |
| Update_note | 140건 |
| IT_Diary | 5건 |
| code_review | 2건 |
| Users | 5명 |
| 미디어 | mkblog-media/ (295 files) |
헬스체크: GET /health/ → DB 경로 + posts 수 반환
| 원인 | 설명 |
|---|---|
| OOM (메모리 부족) | 512MB에서 Docker + Nginx + Gunicorn + collectstatic + --build 시 메모리 초과 |
| SQLite WAL 파일 | DB 파일만 마운트하면 WAL/SHM 파일이 컨테이너 내부에만 생성되어 재시작 시 DB 손상 위험 |
| 서버에서 이미지 빌드 | pip compile 시 RAM 급증 → 프로세스 kill |
- 프로젝트 디렉터리 전체 마운트 (
./:/data/project) → WAL 파일 호스트에 저장 - Gunicorn workers=1, threads=2 → SQLite 동시 접근 + 메모리 절약
- 메모리 limit web 384MB, nginx 64MB
- CI에서 이미지 빌드 → GHCR push → 서버는 pull만 (서버에서 build 안 함)
- 1GB Swap (
scripts/lightsail-setup.sh) - collectstatic 1회만 (static volume sentinel)
/health/엔드포인트로 DB 연결 확인
# SSH 접속
ssh -i django.pem ubuntu@<LIGHTSAIL_IP>
# 스크립트 실행
bash scripts/lightsail-setup.shLightsail 콘솔 → Networking → HTTP(80), HTTPS(443) 포트 열기
# 로컬 PC에서
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/<USER>/<REPO>.git
git push -u origin main
# DB/미디어 서버 업로드 (Git에 포함하지 않음)
scp -i django.pem mkblog-db.sqlite3 ubuntu@<IP>:/home/ubuntu/Django_Blog/Django_Blog_Back/
scp -i django.pem -r mkblog-media ubuntu@<IP>:/home/ubuntu/Django_Blog/Django_Blog_Back/서버에서:
cd /home/ubuntu/Django_Blog/Django_Blog_Back
git clone https://github.com/<USER>/<REPO>.git .
cp .env.server.example .env.server
nano .env.server # SECRET_KEY, ALLOWED_HOSTS, DOCKER_IMAGE 수정Repository → Settings → Secrets → Actions:
| Secret | 값 | 필수 |
|---|---|---|
SERVER_HOST |
Lightsail IP | ✅ |
SERVER_USER |
ubuntu |
✅ |
SSH_PRIVATE_KEY |
django.pem 파일 내용 전체 |
✅ |
DEPLOY_PATH |
/home/ubuntu/Django_Blog/Django_Blog_Back |
✅ |
GHCR_TOKEN |
GitHub PAT (read:packages, write:packages) |
✅ |
SERVER_PORT |
22 (기본값) |
선택 |
GHCR_TOKEN 생성: GitHub → Settings → Developer settings → Personal access tokens → read:packages, write:packages 권한
GHCR 패키지 공개 (선택): GitHub → Packages → miky-blog → Package settings → Change visibility → Public
# main 브랜치 push → 자동 CD
git push origin main수동 배포 (서버):
cd /home/ubuntu/Django_Blog/Django_Blog_Back
docker compose -f docker-compose.server.yml up -d
bash scripts/server-check.shcurl http://<LIGHTSAIL_IP>/health/
# {"status": "ok", "database": "/data/project/mkblog-db.sqlite3", "posts": 264}브라우저: http://<LIGHTSAIL_IP>/ 또는 도메인
cp .env.local.example .env.local
docker compose -f docker-compose.local.yml up --build브라우저: http://localhost:8000 (nginx → gunicorn)
push main
├─ CI (develop/PR): check → test → docker build
└─ CD (main):
1. GitHub Actions에서 Docker 이미지 빌드
2. ghcr.io/<user>/<repo>/miky-blog:latest push
3. SSH → Lightsail
4. docker compose pull (빌드 없음)
5. docker compose up -d
6. /health/ 확인
| 항목 | 값 |
|---|---|
| IP | 3.37.248.157 |
| 도메인 | https://mikysdailylife.com/ |
Networking → IPv4 Firewall:
- SSH
22 - HTTP
80 - HTTPS
443
# 프로젝트 + DB + 미디어 (pem 경로 맞게 수정)
scp -i django.pem -r Django_Blog_Back ubuntu@3.37.248.157:/home/ubuntu/Django_Blog/또는 서버에서 git clone 후 DB만 업로드:
scp -i django.pem mkblog-db.sqlite3 ubuntu@3.37.248.157:/home/ubuntu/Django_Blog/Django_Blog_Back/
scp -i django.pem -r mkblog-media ubuntu@3.37.248.157:/home/ubuntu/Django_Blog/Django_Blog_Back/ssh -i django.pem ubuntu@3.37.248.157
cd /home/ubuntu/Django_Blog/Django_Blog_Back
# 예전 gunicorn/nginx가 80포트를 쓰고 있으면 중지
sudo systemctl stop gunicorn 2>/dev/null || true
sudo systemctl stop nginx 2>/dev/null || true
# 최초 1회: Swap + Docker + Watchdog
sudo bash scripts/lightsail-setup.sh
# 앱 기동 (env 생성 + docker build + up)
bash scripts/deploy-lightsail.shcurl http://127.0.0.1/health/
curl http://3.37.248.157/health/
# 브라우저: https://mikysdailylife.com/설정값 (.env.server.example에 반영됨):
ALLOWED_HOSTS=mikysdailylife.com,www.mikysdailylife.com,3.37.248.157,...CSRF_TRUSTED_ORIGINS=https://mikysdailylife.com,https://www.mikysdailylife.com
| Secret | 값 |
|---|---|
SERVER_HOST |
3.37.248.157 |
SERVER_USER |
ubuntu |
SSH_PRIVATE_KEY |
pem 전체 |
DEPLOY_PATH |
/home/ubuntu/Django_Blog/Django_Blog_Back |
Lightsail 512MB에서 중단은 보통 메모리(OOM) 또는 디스크 full 입니다.
cd /home/ubuntu/Django_Blog/Django_Blog_Back
bash scripts/diagnose-crash.sh
# 설치 후:
miky-blog-diagnose| 결론 | 의미 |
|---|---|
memory |
OOM Killer가 프로세스 kill (가장 흔함) |
disk |
/ 파티션 용량 부족 (Docker 로그/이미지) |
memory+disk |
둘 다 위험 |
sudo bash scripts/install-watchdog.sh2분마다 실행:
- 메모리 >= 88% 또는 가용 <= 40MB → cache/docker prune → compose 재시작
- 디스크 >= 85% → docker/journal/apt 정리 → compose 재시작
/health/실패 → compose 강제 재기동
tail -f /var/log/miky-blog/watchdog.log
systemctl status miky-blog-watchdog.timer
bash scripts/server-check.sh초기 세팅(Swap + Docker 로그 로테이션 + Watchdog):
sudo bash scripts/lightsail-setup.sh자세한 아키텍처/디렉터리/요청 흐름은 아래 문서를 참고하세요.
Django_Blog_Back/
├── mkblog-db.sqlite3 # SQLite DB (Git 제외, volume mount)
├── mkblog-media/ # 업로드 파일 (Git 제외)
├── Blog/ # Django 앱
├── docker/
├── docker-compose.local.yml
├── docker-compose.server.yml
├── docs/
│ └── ARCHITECTURE.md # 전체 구조 문서
├── scripts/
│ ├── diagnose-crash.sh # 메모리 vs 디스크 원인 판별
│ ├── watchdog.sh # 임계치 초과 시 정리+재시작
│ ├── install-watchdog.sh # systemd timer 설치
│ ├── setup-https.sh # 호스트 HTTPS → Docker 8080
│ ├── lightsail-setup.sh
│ └── server-check.sh
└── .env.server # 서버 비밀값 (Git 제외)