Skip to content

Commit f398c94

Browse files
committed
Ci for aws v1
1 parent 83de7a0 commit f398c94

File tree

2 files changed

+243
-456
lines changed

2 files changed

+243
-456
lines changed

.github/workflows/build-ecr.yml

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
name: Build and Push to ECR
2+
3+
on:
4+
push:
5+
branches: [main, staging]
6+
7+
permissions:
8+
id-token: write
9+
contents: read
10+
11+
jobs:
12+
build-and-push-ecr:
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
include:
17+
- dockerfile: ./docker/app.Dockerfile
18+
ecr_repo_secret: ECR_APP
19+
service_type: app
20+
- dockerfile: ./docker/db.Dockerfile
21+
ecr_repo_secret: ECR_MIGRATIONS
22+
service_type: core
23+
- dockerfile: ./docker/realtime.Dockerfile
24+
ecr_repo_secret: ECR_REALTIME
25+
service_type: monitoring
26+
runs-on: ubuntu-latest
27+
28+
steps:
29+
- name: Checkout repository
30+
uses: actions/checkout@v4
31+
32+
- name: Configure AWS credentials
33+
uses: aws-actions/configure-aws-credentials@v4
34+
with:
35+
role-to-assume: ${{ github.ref == 'refs/heads/main' && secrets.AWS_ROLE_TO_ASSUME || secrets.STAGING_AWS_ROLE_TO_ASSUME }}
36+
aws-region: ${{ github.ref == 'refs/heads/main' && secrets.AWS_REGION || secrets.STAGING_AWS_REGION }}
37+
38+
- name: Login to Amazon ECR
39+
id: login-ecr
40+
uses: aws-actions/amazon-ecr-login@v2
41+
42+
- name: Set up Docker Buildx
43+
uses: docker/setup-buildx-action@v3
44+
45+
- name: Generate image tags
46+
id: meta
47+
run: |
48+
ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}"
49+
ECR_REPO="${{ secrets[matrix.ecr_repo_secret] }}"
50+
51+
# Simple tagging: :latest for main, :staging for staging
52+
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
53+
TAG="latest"
54+
else
55+
TAG="staging"
56+
fi
57+
58+
FULL_IMAGE="${ECR_REGISTRY}/${ECR_REPO}:${TAG}"
59+
60+
echo "tag=$TAG" >> $GITHUB_OUTPUT
61+
echo "full_image=$FULL_IMAGE" >> $GITHUB_OUTPUT
62+
63+
- name: Build and push Docker image
64+
uses: docker/build-push-action@v6
65+
with:
66+
context: .
67+
file: ${{ matrix.dockerfile }}
68+
push: true
69+
tags: ${{ steps.meta.outputs.full_image }}
70+
platforms: linux/amd64
71+
cache-from: type=gha,scope=build-ecr-${{ matrix.service_type }}
72+
cache-to: type=gha,mode=max,scope=build-ecr-${{ matrix.service_type }}
73+
provenance: false
74+
sbom: false
75+
76+
update-ecs-services:
77+
needs: build-and-push-ecr
78+
runs-on: ubuntu-latest
79+
strategy:
80+
fail-fast: false
81+
matrix:
82+
stack_type: [APP, CORE, MONITORING]
83+
84+
steps:
85+
- name: Configure AWS credentials
86+
uses: aws-actions/configure-aws-credentials@v4
87+
with:
88+
role-to-assume: ${{ github.ref == 'refs/heads/main' && secrets.AWS_ROLE_TO_ASSUME || secrets.STAGING_AWS_ROLE_TO_ASSUME }}
89+
aws-region: ${{ github.ref == 'refs/heads/main' && secrets.AWS_REGION || secrets.STAGING_AWS_REGION }}
90+
91+
- name: Login to Amazon ECR
92+
id: login-ecr
93+
uses: aws-actions/amazon-ecr-login@v2
94+
95+
- name: Determine stack and image details
96+
id: stack
97+
run: |
98+
ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}"
99+
100+
# Determine stack prefix and tag based on environment
101+
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
102+
STACK_PREFIX="PROD"
103+
TAG="latest"
104+
else
105+
STACK_PREFIX="STAGING"
106+
TAG="staging"
107+
fi
108+
109+
# Map stack type to ECR repo and get stack name
110+
case "${{ matrix.stack_type }}" in
111+
APP)
112+
STACK_NAME_VAR="${STACK_PREFIX}_APP_STACK"
113+
ECR_REPO="${{ secrets.ECR_APP }}"
114+
;;
115+
CORE)
116+
STACK_NAME_VAR="${STACK_PREFIX}_CORE_STACK"
117+
ECR_REPO="${{ secrets.ECR_MIGRATIONS }}"
118+
;;
119+
MONITORING)
120+
STACK_NAME_VAR="${STACK_PREFIX}_MONITORING_STACK"
121+
ECR_REPO="${{ secrets.ECR_REALTIME }}"
122+
;;
123+
esac
124+
125+
# Get stack name from secrets
126+
STACK_NAME=$(eval echo \${{ secrets.${STACK_NAME_VAR} }})
127+
128+
# Full image URI with simple tag
129+
IMAGE_URI="${ECR_REGISTRY}/${ECR_REPO}:${TAG}"
130+
131+
echo "name=$STACK_NAME" >> $GITHUB_OUTPUT
132+
echo "image=$IMAGE_URI" >> $GITHUB_OUTPUT
133+
134+
- name: Get ECS services from stack
135+
id: ecs-services
136+
run: |
137+
# Get all ECS services from the stack
138+
SERVICES=$(aws cloudformation describe-stack-resources \
139+
--stack-name "${{ steps.stack.outputs.name }}" \
140+
--query "StackResources[?ResourceType=='AWS::ECS::Service'].PhysicalResourceId" \
141+
--output text 2>/dev/null || echo "")
142+
143+
if [ -z "$SERVICES" ]; then
144+
echo "No ECS services found in stack ${{ steps.stack.outputs.name }}"
145+
echo "services=" >> $GITHUB_OUTPUT
146+
else
147+
echo "Found services: $SERVICES"
148+
echo "services=$SERVICES" >> $GITHUB_OUTPUT
149+
fi
150+
151+
- name: Update ECS services
152+
if: steps.ecs-services.outputs.services != ''
153+
run: |
154+
SERVICES="${{ steps.ecs-services.outputs.services }}"
155+
156+
for SERVICE_ARN in $SERVICES; do
157+
echo "Updating service: $SERVICE_ARN"
158+
159+
# Extract cluster name from service ARN
160+
CLUSTER_NAME=$(echo $SERVICE_ARN | cut -d'/' -f2)
161+
SERVICE_NAME=$(echo $SERVICE_ARN | cut -d'/' -f3)
162+
163+
# Get the current task definition
164+
TASK_DEF_ARN=$(aws ecs describe-services \
165+
--cluster "$CLUSTER_NAME" \
166+
--services "$SERVICE_NAME" \
167+
--query "services[0].taskDefinition" \
168+
--output text)
169+
170+
# Get the task definition details
171+
TASK_DEF=$(aws ecs describe-task-definition \
172+
--task-definition "$TASK_DEF_ARN" \
173+
--query "taskDefinition")
174+
175+
# Update the image in the task definition
176+
# For Ubuntu ECS, container definitions may have multiple containers
177+
NEW_TASK_DEF=$(echo "$TASK_DEF" | jq --arg IMAGE "${{ steps.stack.outputs.image }}" \
178+
'.containerDefinitions |= map(
179+
if .essential == true then
180+
.image = $IMAGE
181+
else . end
182+
) |
183+
del(.taskDefinitionArn) |
184+
del(.revision) |
185+
del(.status) |
186+
del(.requiresAttributes) |
187+
del(.compatibilities) |
188+
del(.registeredAt) |
189+
del(.registeredBy)')
190+
191+
# Register new task definition
192+
NEW_TASK_ARN=$(aws ecs register-task-definition \
193+
--cli-input-json "$NEW_TASK_DEF" \
194+
--query "taskDefinition.taskDefinitionArn" \
195+
--output text)
196+
197+
echo "Registered new task definition: $NEW_TASK_ARN"
198+
199+
# Update service with new task definition
200+
aws ecs update-service \
201+
--cluster "$CLUSTER_NAME" \
202+
--service "$SERVICE_NAME" \
203+
--task-definition "$NEW_TASK_ARN" \
204+
--force-new-deployment
205+
206+
echo "Service update initiated for $SERVICE_NAME"
207+
done
208+
209+
- name: Wait for service stability
210+
if: steps.ecs-services.outputs.services != ''
211+
run: |
212+
SERVICES="${{ steps.ecs-services.outputs.services }}"
213+
214+
for SERVICE_ARN in $SERVICES; do
215+
CLUSTER_NAME=$(echo $SERVICE_ARN | cut -d'/' -f2)
216+
SERVICE_NAME=$(echo $SERVICE_ARN | cut -d'/' -f3)
217+
218+
echo "Waiting for service $SERVICE_NAME to stabilize..."
219+
220+
# Wait up to 30 minutes for service to stabilize
221+
ATTEMPTS=0
222+
MAX_ATTEMPTS=120
223+
while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
224+
DEPLOYMENT_STATUS=$(aws ecs describe-services \
225+
--cluster "$CLUSTER_NAME" \
226+
--services "$SERVICE_NAME" \
227+
--query "services[0].deployments[?status=='PRIMARY'].rolloutState" \
228+
--output text)
229+
230+
if [ "$DEPLOYMENT_STATUS" = "COMPLETED" ]; then
231+
echo "✅ Service $SERVICE_NAME updated successfully!"
232+
break
233+
fi
234+
235+
echo "Deployment status: $DEPLOYMENT_STATUS (attempt $((ATTEMPTS+1))/$MAX_ATTEMPTS)"
236+
sleep 15
237+
ATTEMPTS=$((ATTEMPTS+1))
238+
done
239+
240+
if [ $ATTEMPTS -eq $MAX_ATTEMPTS ]; then
241+
echo "⚠️ Service $SERVICE_NAME did not stabilize within timeout"
242+
fi
243+
done

0 commit comments

Comments
 (0)