1+ name : Build and Deploy Todo API
2+
3+ on :
4+ push :
5+ branches : [main]
6+ workflow_dispatch :
7+
8+ env :
9+ REGISTRY : ghcr.io
10+ IMAGE_NAME : ${{ github.repository }}
11+
12+ jobs :
13+ build-and-push :
14+ runs-on : ubuntu-latest
15+ permissions :
16+ contents : read
17+ packages : write
18+
19+ steps :
20+ - name : Checkout code
21+ uses : actions/checkout@v4
22+
23+ - name : Log in to GitHub Container Registry
24+ uses : docker/login-action@v3
25+ with :
26+ registry : ${{ env.REGISTRY }}
27+ username : ${{ github.actor }}
28+ password : ${{ secrets.GITHUB_TOKEN }}
29+
30+ - name : Extract metadata for Docker
31+ id : meta
32+ uses : docker/metadata-action@v5
33+ with :
34+ images : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
35+ tags : |
36+ type=sha,prefix={{branch}}-
37+ type=raw,value=latest,enable={{is_default_branch}}
38+
39+ - name : Build and push Docker image
40+ uses : docker/build-push-action@v5
41+ with :
42+ context : .
43+ push : true
44+ tags : ${{ steps.meta.outputs.tags }}
45+ labels : ${{ steps.meta.outputs.labels }}
46+
47+ deploy :
48+ needs : build-and-push
49+ runs-on : ubuntu-latest
50+
51+ steps :
52+ - name : Checkout code
53+ uses : actions/checkout@v4
54+
55+ - name : Deploy to remote server
56+ uses : appleboy/ssh-action@v1.0.3
57+ with :
58+ host : ${{ secrets.SERVER_HOST }}
59+ username : ${{ secrets.SERVER_USER }}
60+ key : ${{ secrets.SSH_PRIVATE_KEY }}
61+ script : |
62+ # Create project directory
63+ mkdir -p ~/todo-app
64+ cd ~/todo-app
65+
66+ # Login to GitHub Container Registry
67+ echo ${{ secrets.GITHUB_TOKEN }} | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin
68+
69+ # Stop and remove existing containers
70+ docker-compose down || true
71+
72+ # Pull latest image
73+ docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
74+
75+ # Create docker-compose.yml
76+ cat > docker-compose.yml << 'EOF'
77+ version: '3.8'
78+ services:
79+ mongodb:
80+ image: mongo:7-jammy
81+ container_name: todo-mongodb
82+ restart: unless-stopped
83+ environment:
84+ - MONGO_INITDB_DATABASE=todos
85+ volumes:
86+ - mongodb_data:/data/db
87+ networks:
88+ - todo-network
89+ healthcheck:
90+ test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
91+ interval: 10s
92+ timeout: 5s
93+ retries: 5
94+
95+ api:
96+ image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
97+ container_name: todo-api
98+ restart: unless-stopped
99+ ports:
100+ - "3000:3000"
101+ environment:
102+ - PORT=3000
103+ - MONGODB_URI=mongodb://mongodb:27017/todos
104+ depends_on:
105+ mongodb:
106+ condition: service_healthy
107+ networks:
108+ - todo-network
109+
110+ nginx:
111+ image: nginx:alpine
112+ container_name: todo-nginx
113+ restart: unless-stopped
114+ ports:
115+ - "80:80"
116+ volumes:
117+ - ./nginx.conf:/etc/nginx/nginx.conf:ro
118+ depends_on:
119+ - api
120+ networks:
121+ - todo-network
122+
123+ volumes:
124+ mongodb_data:
125+ driver: local
126+
127+ networks:
128+ todo-network:
129+ driver: bridge
130+ EOF
131+
132+ # Create nginx.conf
133+ cat > nginx.conf << 'EOF'
134+ events {
135+ worker_connections 1024;
136+ }
137+
138+ http {
139+ upstream api {
140+ server api:3000;
141+ }
142+
143+ server {
144+ listen 80;
145+ server_name _;
146+
147+ client_max_body_size 10M;
148+
149+ location / {
150+ proxy_pass http://api;
151+ proxy_http_version 1.1;
152+ proxy_set_header Upgrade $http_upgrade;
153+ proxy_set_header Connection 'upgrade';
154+ proxy_set_header Host $host;
155+ proxy_set_header X-Real-IP $remote_addr;
156+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
157+ proxy_set_header X-Forwarded-Proto $scheme;
158+ proxy_cache_bypass $http_upgrade;
159+ }
160+
161+ location /health {
162+ access_log off;
163+ return 200 "healthy\n";
164+ add_header Content-Type text/plain;
165+ }
166+ }
167+ }
168+ EOF
169+
170+ # Start containers
171+ docker-compose up -d
172+
173+ # Clean up old images
174+ docker image prune -af
0 commit comments