Initial nginx-infra setup with GitOps deployment
- Add GitHub Actions CI/CD pipeline - Configure Nginx reverse proxy for robeing services - Setup docker-compose for full stack deployment - Include health checks for all services - Support for PostgreSQL and Redis data persistence 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
commit
56eaf8c9b5
44
.github/workflows/deploy.yml
vendored
Normal file
44
.github/workflows/deploy.yml
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
name: Deploy Nginx
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Build and push Nginx
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: ./nginx
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
${{ secrets.DOCKER_USERNAME }}/robeing-nginx:latest
|
||||||
|
${{ secrets.DOCKER_USERNAME }}/robeing-nginx:${{ github.sha }}
|
||||||
|
|
||||||
|
- name: Update docker-compose.yml
|
||||||
|
run: |
|
||||||
|
sed -i "s|image: .*/robeing-nginx:.*|image: ${{ secrets.DOCKER_USERNAME }}/robeing-nginx:${{ github.sha }}|g" docker-compose.yml
|
||||||
|
|
||||||
|
- name: Commit and push changes
|
||||||
|
run: |
|
||||||
|
git config --local user.email "action@github.com"
|
||||||
|
git config --local user.name "GitHub Action"
|
||||||
|
git add docker-compose.yml
|
||||||
|
git commit -m "Update nginx image to ${{ github.sha }}" || exit 0
|
||||||
|
git push
|
||||||
68
README.md
Normal file
68
README.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# Nginx Deploy - Robeing Project
|
||||||
|
|
||||||
|
GitOps 방식으로 관리되는 Robeing 프로젝트의 배포 매니페스트 저장소입니다.
|
||||||
|
|
||||||
|
## 구조
|
||||||
|
|
||||||
|
```
|
||||||
|
nginx-deploy/
|
||||||
|
├── .github/workflows/deploy.yml # GitHub Actions CI/CD
|
||||||
|
├── nginx/
|
||||||
|
│ ├── nginx.conf # Nginx 설정
|
||||||
|
│ └── Dockerfile # Nginx 컨테이너 빌드
|
||||||
|
└── docker-compose.yml # 전체 서비스 정의
|
||||||
|
```
|
||||||
|
|
||||||
|
## 배포 플로우
|
||||||
|
|
||||||
|
1. **애플리케이션 저장소**에서 코드 변경 시
|
||||||
|
2. **GitHub Actions**가 새 이미지 빌드 후 Docker Hub에 push
|
||||||
|
3. **Webhook**으로 이 저장소의 `docker-compose.yml` 업데이트
|
||||||
|
4. **수동 또는 자동**으로 서버에 배포
|
||||||
|
|
||||||
|
## 설정
|
||||||
|
|
||||||
|
### GitHub Secrets 설정
|
||||||
|
```
|
||||||
|
DOCKER_USERNAME: Docker Hub 사용자명
|
||||||
|
DOCKER_PASSWORD: Docker Hub 패스워드 또는 토큰
|
||||||
|
```
|
||||||
|
|
||||||
|
### 환경 변수 설정
|
||||||
|
```bash
|
||||||
|
# .env 파일 생성
|
||||||
|
DATABASE_URL=postgresql://user:password@postgres:5432/robeing
|
||||||
|
REDIS_URL=redis://redis:6379/0
|
||||||
|
POSTGRES_USER=robeing
|
||||||
|
POSTGRES_PASSWORD=your-secure-password
|
||||||
|
```
|
||||||
|
|
||||||
|
## 배포 방법
|
||||||
|
|
||||||
|
### 개발 환경
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 프로덕션 배포
|
||||||
|
```bash
|
||||||
|
# 환경 변수 설정 후
|
||||||
|
docker-compose -f docker-compose.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## 서비스 구성
|
||||||
|
|
||||||
|
- **nginx**: 리버스 프록시 (포트 80, 443)
|
||||||
|
- **api-base**: API 서버 (포트 8000)
|
||||||
|
- **test_api**: 테스트 API 서버 (포트 8001)
|
||||||
|
- **frontend**: 프론트엔드 서버 (포트 5173)
|
||||||
|
- **postgres**: PostgreSQL 데이터베이스
|
||||||
|
- **redis**: Redis 캐시
|
||||||
|
|
||||||
|
## Health Check
|
||||||
|
|
||||||
|
모든 서비스는 health check가 설정되어 있으며, `/health` 엔드포인트로 상태 확인 가능합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost/health
|
||||||
|
```
|
||||||
109
docker-compose.yml
Normal file
109
docker-compose.yml
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: your-username/robeing-nginx:latest
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
depends_on:
|
||||||
|
- api-base
|
||||||
|
- test_api
|
||||||
|
- frontend
|
||||||
|
networks:
|
||||||
|
- robeing-network
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
api-base:
|
||||||
|
image: your-username/robeing-api-base:latest
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
|
- REDIS_URL=${REDIS_URL}
|
||||||
|
networks:
|
||||||
|
- robeing-network
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
test_api:
|
||||||
|
image: your-username/robeing-test-api:latest
|
||||||
|
ports:
|
||||||
|
- "8001:8001"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
|
- REDIS_URL=${REDIS_URL}
|
||||||
|
networks:
|
||||||
|
- robeing-network
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: your-username/robeing-frontend:latest
|
||||||
|
ports:
|
||||||
|
- "5173:5173"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- VITE_API_URL=http://localhost/api
|
||||||
|
networks:
|
||||||
|
- robeing-network
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:5173"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=robeing
|
||||||
|
- POSTGRES_USER=${POSTGRES_USER:-robeing}
|
||||||
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- robeing-network
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-robeing}"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
command: redis-server --appendonly yes
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
networks:
|
||||||
|
- robeing-network
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
networks:
|
||||||
|
robeing-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
redis_data:
|
||||||
21
nginx/Dockerfile
Normal file
21
nginx/Dockerfile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
FROM nginx:1.25-alpine
|
||||||
|
|
||||||
|
# Copy custom nginx configuration
|
||||||
|
COPY nginx.conf /etc/nginx/nginx.conf
|
||||||
|
|
||||||
|
# Create log directory
|
||||||
|
RUN mkdir -p /var/log/nginx
|
||||||
|
|
||||||
|
# Set proper permissions
|
||||||
|
RUN chown -R nginx:nginx /var/log/nginx
|
||||||
|
RUN chown -R nginx:nginx /var/cache/nginx
|
||||||
|
|
||||||
|
# Add healthcheck
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD curl -f http://localhost/health || exit 1
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Start nginx
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
96
nginx/nginx.conf
Normal file
96
nginx/nginx.conf
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
user nginx;
|
||||||
|
worker_processes auto;
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
types_hash_max_size 2048;
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_types
|
||||||
|
text/plain
|
||||||
|
text/css
|
||||||
|
text/xml
|
||||||
|
text/javascript
|
||||||
|
application/json
|
||||||
|
application/javascript
|
||||||
|
application/xml+rss
|
||||||
|
application/atom+xml
|
||||||
|
image/svg+xml;
|
||||||
|
|
||||||
|
# Upstream servers
|
||||||
|
upstream api_backend {
|
||||||
|
server api-base:8000;
|
||||||
|
server test_api:8001;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream frontend_backend {
|
||||||
|
server frontend:5173;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main server block
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
# Frontend routing
|
||||||
|
location / {
|
||||||
|
proxy_pass http://frontend_backend;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
# API routing
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://api_backend/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# CORS headers
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type' always;
|
||||||
|
|
||||||
|
if ($request_method = 'OPTIONS') {
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Health check endpoint
|
||||||
|
location /health {
|
||||||
|
access_log off;
|
||||||
|
return 200 "healthy\n";
|
||||||
|
add_header Content-Type text/plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Static files caching
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user