-
-
Notifications
You must be signed in to change notification settings - Fork 1
257 lines (219 loc) · 10.3 KB
/
Copy pathbuild.yml
File metadata and controls
257 lines (219 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
name: Build
permissions:
contents: read
packages: write
on:
push:
tags:
- "*"
jobs:
build:
runs-on: ubuntu-latest
environment: Dev
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
###############################################################
## Frontend
###############################################################
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
cache-dependency-path: frontend/package-lock.json
- name: Install frontend dependencies
working-directory: ./frontend
run: npm ci
- name: Create public directory
working-directory: ./backend
run: mkdir -p src/public
- name: Build frontend
working-directory: ./frontend
run: npm run build
- name: Prune frontend dependencies
working-directory: ./frontend
run: npm prune --production
- name: Save Node dependencies cache
uses: actions/cache@v4
with:
path: |
**/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
###############################################################
## Backend
###############################################################
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Cache Python dependencies
id: cache-python
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
working-directory: ./backend
run: |
env | sort
pip install --upgrade pip
pip install uv
uv sync --frozen --no-cache --no-dev --extra api
- name: Save Python dependencies cache
if: steps.cache-python.outputs.cache-hit != 'true'
id: save-cache-python
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}
###############################################################
## Docker
###############################################################
- name: Copy Docker README and LICENSE to backend
run: |
cp docker/README.md backend/README.md
cp LICENSE backend/LICENSE
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME || github.actor }}
password: ${{ secrets.GHCR_PAT }}
- name: Build and push API image
working-directory: ./backend
run: |
TAG=${GITHUB_REF#refs/tags/}
docker build --target api \
-t ghcr.io/ruska-ai/orchestra-api:$TAG \
-t ghcr.io/ruska-ai/orchestra-api:latest \
-t ghcr.io/ruska-ai/orchestra:$TAG \
-t ghcr.io/ruska-ai/orchestra:latest \
.
docker push ghcr.io/ruska-ai/orchestra-api:$TAG
docker push ghcr.io/ruska-ai/orchestra-api:latest
docker push ghcr.io/ruska-ai/orchestra:$TAG
docker push ghcr.io/ruska-ai/orchestra:latest
- name: Build and push Worker image
working-directory: ./backend
run: |
TAG=${GITHUB_REF#refs/tags/}
docker build --target worker \
-t ghcr.io/ruska-ai/orchestra-worker:$TAG \
-t ghcr.io/ruska-ai/orchestra-worker:latest \
.
docker push ghcr.io/ruska-ai/orchestra-worker:$TAG
docker push ghcr.io/ruska-ai/orchestra-worker:latest
- name: Report image sizes
run: |
echo "## Docker Image Sizes" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Image | Size |" >> $GITHUB_STEP_SUMMARY
echo "|-------|------|" >> $GITHUB_STEP_SUMMARY
docker images ghcr.io/ruska-ai/orchestra-api --format "| API | {{.Size}} |" | head -1 >> $GITHUB_STEP_SUMMARY
docker images ghcr.io/ruska-ai/orchestra-worker --format "| Worker | {{.Size}} |" | head -1 >> $GITHUB_STEP_SUMMARY
deploy:
needs: build
runs-on: ubuntu-latest
environment: Dev
steps:
- name: Deploy to VM
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
GHCR_USERNAME: ${{ secrets.GHCR_USERNAME || github.actor }}
GHCR_TOKEN: ${{ secrets.GHCR_PAT }}
GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/orchestra
run: |
# ---------------------------------------------------
# Setup SSH
# ---------------------------------------------------
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts
ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts
TAG=${{ github.ref_name }}
# ---------------------------------------------------
# SSH into the server and execute deployment
# ---------------------------------------------------
ssh -i ~/.ssh/id_rsa $SSH_USER@$SSH_HOST "
set -e # Exit on error
cd ~/agent_api
echo '--- Logging into GHCR ---'
echo \"$GHCR_TOKEN\" | docker login ghcr.io -u \"$GHCR_USERNAME\" --password-stdin
echo '--- Pulling new images ---'
docker pull $GHCR_IMAGE-api:$TAG
docker pull $GHCR_IMAGE-worker:$TAG
echo '--- Starting staging container (graphchat_new) on port 8006 ---'
docker stop graphchat_new 2>/dev/null || true
docker rm graphchat_new 2>/dev/null || true
docker run -d \
--name graphchat_new \
--network graphchat_default \
--env-file ./backend/.env \
-p 8006:8000 \
$GHCR_IMAGE-api:$TAG
echo '--- Waiting a few seconds for startup ---'
sleep 10
echo '--- Health check on staging container (graphchat_new) ---'
for i in {1..3}; do
if curl -f http://localhost:8006/api/info; then
echo 'New container on port 8006 is healthy!'
break
else
echo \"Attempt \$i failed. Waiting 10 seconds before retry...\"
sleep 10
if [ \$i -eq 3 ]; then
echo 'All retry attempts failed.'
exit 1
fi
fi
done
echo '--- Stopping and removing old container (graphchat) if it exists ---'
docker stop graphchat || true
docker rm graphchat || true
echo '--- Stopping and removing staging container (graphchat_new) ---'
docker stop graphchat_new 2>/dev/null || true
docker rm graphchat_new 2>/dev/null || true
echo '--- Running new container on production port (8005) as graphchat ---'
docker run -d \
--name graphchat \
--network graphchat_default \
--restart always \
--env-file ./backend/.env \
-e APP_VERSION=$TAG \
-e VITE_APP_VERSION=$TAG \
-p 8005:8000 \
$GHCR_IMAGE-api:$TAG
echo '--- Ensuring redis7 is on graphchat_default network ---'
docker network connect graphchat_default redis7 2>/dev/null || echo 'redis7 already on network or not found'
echo '--- Stopping and removing old worker container if it exists ---'
docker stop graphchat_worker 2>/dev/null || true
docker rm graphchat_worker 2>/dev/null || true
echo '--- Starting worker container ---'
docker run -d \
--name graphchat_worker \
--network graphchat_default \
--restart always \
--env-file ./backend/.env \
-e DISTRIBUTED_WORKERS=true \
-e REDIS_URL=redis://redis7:6379/0 \
-e DB_POOL_MIN_SIZE=1 \
-e DB_POOL_MAX_SIZE=5 \
--memory=1g \
--cpus=1 \
$GHCR_IMAGE-worker:$TAG
echo '--- Worker deployment complete ---'
echo '--- Cleaning up old images ---'
docker system prune -a --filter \"until=24h\" -f
echo '--- Deployment successful! ---'
"