-
Notifications
You must be signed in to change notification settings - Fork 1
357 lines (294 loc) · 12 KB
/
deploy.yml
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
name: Deploy SUSDB CI/CD
on:
push:
branches: [ main ]
workflow_dispatch:
inputs:
version_increment:
description: 'Version increment type (major, minor, or patch)'
required: true
default: 'patch'
permissions:
contents: write
packages: write
env:
SECRETS_NAME: susdb
ECR_REPO: susdb
ECR_REGISTRY: 590183661216.dkr.ecr.eu-west-1.amazonaws.com
PROJECT_ID: susdb
S3_BUCKET: susdb
jobs:
build-push-and-tag:
runs-on: ubuntu-latest
outputs:
new_version: ${{ steps.versioning.outputs.new_version }}
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Generate Version
id: versioning
run: |
latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
echo "Latest tag: $latest_tag"
# Remove 'v' prefix if present
latest_version=${latest_tag#v}
# Split the version into an array
IFS='.' read -ra VERSION_PARTS <<< "$latest_version"
MAJOR=${VERSION_PARTS[0]}
MINOR=${VERSION_PARTS[1]}
PATCH=${VERSION_PARTS[2]}
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
case "${{ github.event.inputs.version_increment }}" in
major)
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
;;
minor)
MINOR=$((MINOR + 1))
PATCH=0
;;
patch)
PATCH=$((PATCH + 1))
;;
esac
else
# Auto-increment patch version for push events
PATCH=$((PATCH + 1))
fi
new_version="v$MAJOR.$MINOR.$PATCH"
echo "New version: $new_version"
echo "::set-output name=new_version::$new_version"
- name: Retrieve secrets from AWS Secrets Manager
run: |
echo "Retrieving secrets from AWS Secrets Manager..."
SECRETS=$(aws secretsmanager get-secret-value --secret-id ${{ env.SECRETS_NAME }} --query SecretString --output text)
echo "$SECRETS" | jq -r 'to_entries | map("\(.key)=\(.value)") | .[]' > .env
- name: Temporarily Store .env in s3 config store
run: |
echo "Upload env variables to s3..."
aws s3 cp .env s3://${{ env.S3_BUCKET }}
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.ref }}
restore-keys: |
${{ runner.os }}-buildx-${{ github.ref }}
${{ runner.os }}-buildx
- name: Build and push image to ECR
id: build-image
uses: docker/build-push-action@v6
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: ${{ env.ECR_REPO }}
IMAGE_TAG: ${{ steps.versioning.outputs.new_version }}
with:
context: .
push: true
builder: ${{ steps.buildx.outputs.name }}
tags: |
${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest
cache-from: type=gha,src=/tmp/.buildx-cache
cache-to: type=gha,dest=/tmp/.buildx-cache-new,mode=max
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
if [ -d /tmp/.buildx-cache-new ]; then
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
else
echo "No new cache to move."
fi
shell: /usr/bin/bash -e {0}
- name: Clean up
if: always()
run: rm -f .env
deploy_to_managed_instances:
runs-on: ubuntu-latest
needs:
- build-push-and-tag
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Retrieve Managed Instances by Tags
id: get_instances
run: |
# Fetch instance IDs with specific tags, e.g., Environment=prod
instance_ids=$(aws ec2 describe-instances \
--filters "Name=tag:Project,Values=SUS" "Name=instance-state-name,Values=running" \
--query "Reservations[].Instances[].InstanceId" \
--output text)
# Check if any instances were found
if [ -z "$instance_ids" ]; then
echo "No instances found with the specified tags."
exit 1
fi
echo "Instance IDs: $instance_ids"
echo "::set-output name=instance_ids::$instance_ids"
echo "::set-output name=instance_ids::$instance_ids"
- name: Executing Docker Commands on Instances using SSM
uses: peterkimzz/aws-ssm-send-command@master
id: ssm
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-1
instance-ids: ${{ steps.get_instances.outputs.instance_ids }}
working-directory: /home/ec2-user
comment: "Running docker commands"
command: |
sudo sh -c "set -e && \
export PATH=\$PATH:/usr/local/bin && \
cd /home/ec2-user && \
rm -rf .env.llm && \
echo 'Downloading docker-compose.yml from S3...' && \
aws s3 cp s3://${{ env.S3_BUCKET }}/docker-compose.yml . && \
echo 'Downloading .env from S3...' && \
aws s3 cp s3://${{ env.S3_BUCKET }}/.env . && \
echo 'Stopping existing Docker containers...' && \
/usr/local/bin/docker-compose -f /home/ec2-user/docker-compose.yml down && \
echo 'Logging in to Amazon ECR...' && \
aws ecr get-login-password --region ${{ secrets.AWS_REGION }} | docker login --username AWS --password-stdin ${{ env.ECR_REGISTRY }} && \
echo 'Pulling latest Docker images...' && \
/usr/local/bin/docker-compose -f /home/ec2-user/docker-compose.yml pull && \
echo 'Starting Docker services with Docker Compose...' && \
/usr/local/bin/docker-compose -f /home/ec2-user/docker-compose.yml up -d"
- name: Get the outputs
run: echo "The Command ID is ${{ steps.ssm.outputs.command-id }}"
- name: Check AWS SSM Command Status
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}
run: |
command_id=${{ steps.ssm.outputs.command-id }}
instance_ids=${{ steps.get_instances.outputs.instance_ids }}
# Initial delay to ensure the command has time to start
sleep 10
for instance_id in $instance_ids; do
while true; do
# Fetch the command invocation details
output=$(aws ssm get-command-invocation \
--command-id $command_id \
--instance-id $instance_id \
--output json)
echo "Output: $output"
# Extract the status from the output
status=$(echo $output | jq -r '.Status')
echo "Current status for instance $instance_id: $status"
# Check if the status is Success or Failed
if [[ "$status" == "Success" ]]; then
echo "Final status for instance $instance_id: $status"
break
elif [[ "$status" == "Failed" ]]; then
echo "Commands failed on instance $instance_id. Ending the pipeline."
exit 1
fi
# Delay before the next status check
sleep 60
done
done
- name: Remove env file from s3
if: always()
run: aws s3 rm s3://${{ env.S3_BUCKET }}/.env
create-release:
needs:
- build-push-and-tag
- deploy_to_managed_instances
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Generate Release Notes
id: generate_release_notes
run: |
# Get the latest tag
latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
# Get the new version tag from the previous job
new_version="${{ needs.build-push-and-tag.outputs.new_version }}"
# If there's no previous tag, use the initial commit
if [ -z "$latest_tag" ]; then
latest_tag=$(git rev-list --max-parents=0 HEAD)
fi
# Fetch the commit messages between the latest tag and HEAD
release_notes=$(git log ${latest_tag}..HEAD --pretty=format:"- %s (%h)")
# If there are no commit messages, provide a default message
if [ -z "$release_notes" ]; then
release_notes="- Initial release"
fi
echo "Generated release notes:"
echo "$release_notes"
# Escape newlines and quote special characters for GitHub Actions
release_notes="${release_notes//'%'/'%25'}"
release_notes="${release_notes//$'\n'/'%0A'}"
release_notes="${release_notes//$'\r'/'%0D'}"
# Save the release notes as output
echo "::set-output name=release_notes::$release_notes"
- name: Check for existing release
id: check_release
run: |
release_id=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/releases/tags/${{ needs.build-push-and-tag.outputs.new_version }}" \
| jq -r '.id')
if [ "$release_id" != "null" ]; then
echo "::set-output name=release_exists::true"
echo "::set-output name=release_id::$release_id"
else
echo "::set-output name=release_exists::false"
fi
- name: Update existing release
if: steps.check_release.outputs.release_exists == 'true'
run: |
curl -X PATCH \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/releases/${{ steps.check_release.outputs.release_id }}" \
-d '{
"tag_name": "${{ needs.build-push-and-tag.outputs.new_version }}",
"name": "Release ${{ needs.build-push-and-tag.outputs.new_version }}",
"body": "${{ steps.generate_release_notes.outputs.release_notes }}"
}'
- name: Create Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.build-push-and-tag.outputs.new_version }}
release_name: Release ${{ needs.build-push-and-tag.outputs.new_version }}
body: ${{ steps.generate_release_notes.outputs.release_notes }}
draft: false
prerelease: false
- name: Update version file
run: |
echo "${{ needs.build-push-and-tag.outputs.new_version }}" > VERSION
git config user.name Terre8055
git config user.email michaelappiah2018@icloud.com
git add VERSION
git commit -m "Bump version to ${{ needs.build-push-and-tag.outputs.new_version }}"
git pull --no-edit origin main
git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}