Skip to content

Commit 49cb228

Browse files
committed
github workflow changes
1 parent 46d009f commit 49cb228

2 files changed

Lines changed: 257 additions & 21 deletions

File tree

.github/workflows/docker-build.yml

Lines changed: 249 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build and Push Docker Images
1+
name: Build, Push, and Deploy to EC2
22

33
on:
44
push:
@@ -8,30 +8,189 @@ on:
88
branches:
99
- master
1010
workflow_dispatch:
11+
inputs:
12+
force_rebuild:
13+
description: "Force rebuild of all Docker images"
14+
required: false
15+
default: false
16+
type: boolean
1117

1218
permissions:
1319
contents: read
1420

21+
env:
22+
DOCKER_REGISTRY: docker.io
23+
DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
24+
DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}
25+
1526
jobs:
16-
build-and-push:
17-
name: Build and Push ${{ matrix.service }}
27+
detect-changes:
28+
name: Detect Changes
1829
runs-on: ubuntu-latest
30+
outputs:
31+
backends: ${{ steps.set-services.outputs.backends }}
32+
frontends: ${{ steps.set-services.outputs.frontends }}
33+
has_backend_changes: ${{ steps.set-services.outputs.has_backend_changes }}
34+
has_frontend_changes: ${{ steps.set-services.outputs.has_frontend_changes }}
35+
steps:
36+
- name: Checkout Repository
37+
uses: actions/checkout@v4
38+
39+
- name: Check for changes
40+
id: filter
41+
uses: dorny/paths-filter@v3
42+
with:
43+
filters: |
44+
api-gateway:
45+
- 'apps/api-gateway/**'
46+
- 'packages/**'
47+
- 'package.json'
48+
- 'pnpm-lock.yaml'
49+
- 'pnpm-workspace.yaml'
50+
- 'tsconfig.base.json'
51+
- 'nx.json'
52+
auth-service:
53+
- 'apps/auth-service/**'
54+
- 'packages/**'
55+
- 'package.json'
56+
- 'pnpm-lock.yaml'
57+
- 'pnpm-workspace.yaml'
58+
- 'tsconfig.base.json'
59+
- 'nx.json'
60+
product-service:
61+
- 'apps/product-service/**'
62+
- 'packages/**'
63+
- 'package.json'
64+
- 'pnpm-lock.yaml'
65+
- 'pnpm-workspace.yaml'
66+
- 'tsconfig.base.json'
67+
- 'nx.json'
68+
order-service:
69+
- 'apps/order-service/**'
70+
- 'packages/**'
71+
- 'package.json'
72+
- 'pnpm-lock.yaml'
73+
- 'pnpm-workspace.yaml'
74+
- 'tsconfig.base.json'
75+
- 'nx.json'
76+
admin-service:
77+
- 'apps/admin-service/**'
78+
- 'packages/**'
79+
- 'package.json'
80+
- 'pnpm-lock.yaml'
81+
- 'pnpm-workspace.yaml'
82+
- 'tsconfig.base.json'
83+
- 'nx.json'
84+
chatting-service:
85+
- 'apps/chatting-service/**'
86+
- 'packages/**'
87+
- 'package.json'
88+
- 'pnpm-lock.yaml'
89+
- 'pnpm-workspace.yaml'
90+
- 'tsconfig.base.json'
91+
- 'nx.json'
92+
recommendation-service:
93+
- 'apps/recommendation-service/**'
94+
- 'packages/**'
95+
- 'package.json'
96+
- 'pnpm-lock.yaml'
97+
- 'pnpm-workspace.yaml'
98+
- 'tsconfig.base.json'
99+
- 'nx.json'
100+
logger-service:
101+
- 'apps/logger-service/**'
102+
- 'packages/**'
103+
- 'package.json'
104+
- 'pnpm-lock.yaml'
105+
- 'pnpm-workspace.yaml'
106+
- 'tsconfig.base.json'
107+
- 'nx.json'
108+
kafka-consumer:
109+
- 'apps/kafka/**'
110+
- 'packages/**'
111+
- 'package.json'
112+
- 'pnpm-lock.yaml'
113+
- 'pnpm-workspace.yaml'
114+
- 'tsconfig.base.json'
115+
- 'nx.json'
116+
user-ui:
117+
- 'apps/user-ui/**'
118+
- 'packages/**'
119+
- 'package.json'
120+
- 'pnpm-lock.yaml'
121+
- 'pnpm-workspace.yaml'
122+
- 'tsconfig.base.json'
123+
- 'nx.json'
124+
seller-ui:
125+
- 'apps/seller-ui/**'
126+
- 'packages/**'
127+
- 'package.json'
128+
- 'pnpm-lock.yaml'
129+
- 'pnpm-workspace.yaml'
130+
- 'tsconfig.base.json'
131+
- 'nx.json'
132+
admin-ui:
133+
- 'apps/admin-ui/**'
134+
- 'packages/**'
135+
- 'package.json'
136+
- 'pnpm-lock.yaml'
137+
- 'pnpm-workspace.yaml'
138+
- 'tsconfig.base.json'
139+
- 'nx.json'
140+
141+
- name: Set services output
142+
id: set-services
143+
run: |
144+
FORCE="${{ github.event.inputs.force_rebuild }}"
145+
BACKENDS=()
146+
FRONTENDS=()
147+
148+
if [ "$FORCE" = "true" ]; then
149+
BACKENDS=("api-gateway" "auth-service" "product-service" "order-service" "admin-service" "chatting-service" "recommendation-service" "logger-service" "kafka-consumer")
150+
FRONTENDS=("user-ui" "seller-ui" "admin-ui")
151+
else
152+
if [ "${{ steps.filter.outputs.api-gateway }}" = "true" ]; then BACKENDS+=("api-gateway"); fi
153+
if [ "${{ steps.filter.outputs.auth-service }}" = "true" ]; then BACKENDS+=("auth-service"); fi
154+
if [ "${{ steps.filter.outputs.product-service }}" = "true" ]; then BACKENDS+=("product-service"); fi
155+
if [ "${{ steps.filter.outputs.order-service }}" = "true" ]; then BACKENDS+=("order-service"); fi
156+
if [ "${{ steps.filter.outputs.admin-service }}" = "true" ]; then BACKENDS+=("admin-service"); fi
157+
if [ "${{ steps.filter.outputs.chatting-service }}" = "true" ]; then BACKENDS+=("chatting-service"); fi
158+
if [ "${{ steps.filter.outputs.recommendation-service }}" = "true" ]; then BACKENDS+=("recommendation-service"); fi
159+
if [ "${{ steps.filter.outputs.logger-service }}" = "true" ]; then BACKENDS+=("logger-service"); fi
160+
if [ "${{ steps.filter.outputs.kafka-consumer }}" = "true" ]; then BACKENDS+=("kafka-consumer"); fi
161+
162+
if [ "${{ steps.filter.outputs.user-ui }}" = "true" ]; then FRONTENDS+=("user-ui"); fi
163+
if [ "${{ steps.filter.outputs.seller-ui }}" = "true" ]; then FRONTENDS+=("seller-ui"); fi
164+
if [ "${{ steps.filter.outputs.admin-ui }}" = "true" ]; then FRONTENDS+=("admin-ui"); fi
165+
fi
166+
167+
if [ ${#BACKENDS[@]} -eq 0 ]; then
168+
echo "backends=[]" >> $GITHUB_OUTPUT
169+
echo "has_backend_changes=false" >> $GITHUB_OUTPUT
170+
else
171+
JSON_BACKENDS=$(printf '%s\n' "${BACKENDS[@]}" | jq -R . | jq -s -c .)
172+
echo "backends=$JSON_BACKENDS" >> $GITHUB_OUTPUT
173+
echo "has_backend_changes=true" >> $GITHUB_OUTPUT
174+
fi
175+
176+
if [ ${#FRONTENDS[@]} -eq 0 ]; then
177+
echo "frontends=[]" >> $GITHUB_OUTPUT
178+
echo "has_frontend_changes=false" >> $GITHUB_OUTPUT
179+
else
180+
JSON_FRONTENDS=$(printf '%s\n' "${FRONTENDS[@]}" | jq -R . | jq -s -c .)
181+
echo "frontends=$JSON_FRONTENDS" >> $GITHUB_OUTPUT
182+
echo "has_frontend_changes=true" >> $GITHUB_OUTPUT
183+
fi
184+
185+
build-backend:
186+
name: Build Backend ${{ matrix.service }}
187+
runs-on: ubuntu-latest
188+
needs: detect-changes
189+
if: needs.detect-changes.outputs.has_backend_changes == 'true'
19190
strategy:
20191
fail-fast: false
21192
matrix:
22-
service:
23-
- api-gateway
24-
- auth-service
25-
- product-service
26-
- order-service
27-
- admin-service
28-
- chatting-service
29-
- recommendation-service
30-
- logger-service
31-
- kafka-consumer
32-
- user-ui
33-
- seller-ui
34-
- admin-ui
193+
service: ${{ fromJson(needs.detect-changes.outputs.backends) }}
35194

36195
steps:
37196
- name: Checkout Repository
@@ -47,8 +206,8 @@ jobs:
47206
if: github.event_name != 'pull_request'
48207
uses: docker/login-action@v3
49208
with:
50-
username: ${{ secrets.DOCKER_USERNAME }}
51-
password: ${{ secrets.DOCKER_PASSWORD }}
209+
username: ${{ secrets.DOCKERHUB_USERNAME }}
210+
password: ${{ secrets.DOCKERHUB_TOKEN }}
52211

53212
- name: Set Dockerfile path
54213
id: vars
@@ -67,7 +226,77 @@ jobs:
67226
file: ${{ steps.vars.outputs.dockerfile }}
68227
push: ${{ github.event_name != 'pull_request' }}
69228
tags: |
70-
${{ secrets.DOCKER_USERNAME || 'eshop' }}/${{ matrix.service }}:latest
71-
${{ secrets.DOCKER_USERNAME || 'eshop' }}/${{ matrix.service }}:${{ github.sha }}
229+
${{ secrets.DOCKERHUB_USERNAME || 'eshop' }}/${{ matrix.service }}:latest
230+
${{ secrets.DOCKERHUB_USERNAME || 'eshop' }}/${{ matrix.service }}:${{ github.sha }}
231+
cache-from: type=gha,scope=${{ matrix.service }}
232+
cache-to: type=gha,mode=max,scope=${{ matrix.service }}
233+
234+
build-frontend:
235+
name: Build Frontend ${{ matrix.service }}
236+
runs-on: ubuntu-latest
237+
needs: detect-changes
238+
if: needs.detect-changes.outputs.has_frontend_changes == 'true'
239+
strategy:
240+
fail-fast: false
241+
matrix:
242+
service: ${{ fromJson(needs.detect-changes.outputs.frontends) }}
243+
244+
steps:
245+
- name: Checkout Repository
246+
uses: actions/checkout@v4
247+
248+
- name: Set up QEMU
249+
uses: docker/setup-qemu-action@v3
250+
251+
- name: Set up Docker Buildx
252+
uses: docker/setup-buildx-action@v3
253+
254+
- name: Log in to Docker Hub
255+
if: github.event_name != 'pull_request'
256+
uses: docker/login-action@v3
257+
with:
258+
username: ${{ secrets.DOCKERHUB_USERNAME }}
259+
password: ${{ secrets.DOCKERHUB_TOKEN }}
260+
261+
- name: Build and Push Image
262+
uses: docker/build-push-action@v5
263+
with:
264+
context: .
265+
file: apps/${{ matrix.service }}/Dockerfile
266+
push: ${{ github.event_name != 'pull_request' }}
267+
tags: |
268+
${{ secrets.DOCKERHUB_USERNAME || 'eshop' }}/${{ matrix.service }}:latest
269+
${{ secrets.DOCKERHUB_USERNAME || 'eshop' }}/${{ matrix.service }}:${{ github.sha }}
72270
cache-from: type=gha,scope=${{ matrix.service }}
73271
cache-to: type=gha,mode=max,scope=${{ matrix.service }}
272+
273+
deploy:
274+
name: Deploy to EC2
275+
runs-on: ubuntu-latest
276+
needs: [detect-changes, build-backend, build-frontend]
277+
if: |
278+
always() &&
279+
github.event_name != 'pull_request' &&
280+
(needs.detect-changes.outputs.has_backend_changes == 'true' || needs.detect-changes.outputs.has_frontend_changes == 'true') &&
281+
(needs.build-backend.result == 'success' || needs.build-backend.result == 'skipped') &&
282+
(needs.build-frontend.result == 'success' || needs.build-frontend.result == 'skipped')
283+
steps:
284+
- name: Checkout Repository
285+
uses: actions/checkout@v4
286+
287+
- name: Set up SSH Private Key
288+
run: |
289+
cat << 'EOF' > key.pem
290+
${{ secrets.EC2_PRIVATE_KEY }}
291+
EOF
292+
chmod 600 key.pem
293+
294+
- name: Run Deployment Script
295+
env:
296+
EC2_HOST: ${{ secrets.EC2_HOST }}
297+
SSH_KEY_PATH: ./key.pem
298+
DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
299+
DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}
300+
run: |
301+
chmod +x scripts/deploy-production.sh
302+
./scripts/deploy-production.sh

scripts/deploy-production.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,16 @@ deploy_remote() {
5656
ssh -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=no ubuntu@"$EC2_HOST" "sudo mkdir -p $APP_DIR && sudo chown -R ubuntu:ubuntu $APP_DIR"
5757

5858
scp -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=no \
59-
docker-compose.production.yml nginx.conf .env \
59+
docker-compose.production.yml nginx.conf \
6060
ubuntu@"$EC2_HOST":"$APP_DIR"
6161

62+
if [ -f .env ]; then
63+
echo ">>> Copying local .env file to EC2..."
64+
scp -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=no .env ubuntu@"$EC2_HOST":"$APP_DIR"
65+
else
66+
echo ">>> No local .env file found. Skipping .env copy (assuming it is already configured on EC2)..."
67+
fi
68+
6269
# 2. Run remote deploy commands
6370
echo ">>> Executing deployment commands on EC2..."
6471
ssh -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=no ubuntu@"$EC2_HOST" \

0 commit comments

Comments
 (0)