Skip to content

Commit 330a0ca

Browse files
authored
Merge pull request #1975 from hackforla/backendBuild
2 parents ffc3bc6 + a76183b commit 330a0ca

File tree

3 files changed

+147
-85
lines changed

3 files changed

+147
-85
lines changed

.github/workflows/aws-backend-deploy.yml

Lines changed: 95 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ on:
44
inputs:
55
env:
66
type: choice
7-
description: 'AWS Incubator Env'
8-
options:
9-
- dev
10-
- prod
7+
description: "AWS Incubator Env"
8+
options:
9+
- dev
10+
- prod
1111
ref:
12-
description: 'Branch, Tag, or SHA'
12+
description: "Branch, Tag, or SHA"
1313
required: true
1414
env:
1515
AWS_SHARED_CLUSTER: incubator-prod
@@ -19,95 +19,108 @@ env:
1919
DOCKER_PATH: backend
2020
jobs:
2121
setup_env:
22-
name: Set-up environment
22+
name: Set-up environment
2323
runs-on: ubuntu-latest
2424
steps:
25-
- name: Debug Action
26-
uses: hmarr/debug-action@v1.0.0
27-
- name: Checkout
28-
uses: actions/checkout@v4
29-
with:
30-
ref: ${{ github.event.inputs.ref }}
31-
- name: Set AWS Env & Image Tag per workflow
32-
run: |
33-
SHORT_SHA=$(git rev-parse --short HEAD)
34-
if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
35-
INPUT_ENV=${{ github.event.inputs.env }}; INPUT_REF=${{ github.event.inputs.ref }}
36-
echo AWS_APPENV="$AWS_APP_NAME"-$INPUT_ENV >> $GITHUB_ENV
37-
echo IMAGE_TAG=$SHORT_SHA >> $GITHUB_ENV
38-
fi
25+
- name: Debug Action
26+
uses: hmarr/debug-action@v1.0.0
27+
- name: Checkout
28+
uses: actions/checkout@v4
29+
with:
30+
ref: ${{ github.event.inputs.ref }}
31+
- name: Set AWS Env & Image Tag per workflow
32+
run: |
33+
if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
34+
INPUT_ENV=${{ github.event.inputs.env }}; INPUT_REF=${{ github.event.inputs.ref }}
35+
echo AWS_APPENV="$AWS_APP_NAME"-$INPUT_ENV >> $GITHUB_ENV
36+
echo IMAGE_TAG=$(git rev-parse --short HEAD) >> $GITHUB_ENV
37+
echo BUILD_SHA=$(git rev-parse --short HEAD) >> $GITHUB_ENV
38+
fi
3939
outputs:
4040
AWS_APPENV: ${{ env.AWS_APPENV }}
4141
IMAGE_TAG: ${{ env.IMAGE_TAG }}
42+
BUILD_SHA: ${{ env.BUILD_SHA }}
4243
build:
4344
name: Build & Push Docker Image
4445
runs-on: ubuntu-latest
4546
needs: [setup_env]
4647
steps:
47-
- name: Checkout
48-
uses: actions/checkout@v4
49-
with:
50-
ref: ${{ github.event.inputs.ref }}
51-
- name: Configure AWS credentials
52-
uses: aws-actions/configure-aws-credentials@v1
53-
with:
54-
aws-access-key-id: ${{ secrets.INCUBATOR_AWS_ACCESS_KEY_ID }}
55-
aws-secret-access-key: ${{ secrets.INCUBATOR_AWS_SECRET_ACCESS_KEY }}
56-
aws-region: ${{ env.AWS_REGION }}
57-
- name: Login to Amazon ECR
58-
id: login-ecr
59-
uses: aws-actions/amazon-ecr-login@v1
60-
- name: Init Docker Cache
61-
uses: jpribyl/action-docker-layer-caching@v0.1.0
62-
with:
63-
key: ${{ github.workflow }}-2-{hash}
64-
restore-keys: |
65-
${{ github.workflow }}-2-
66-
- name: Build & Push Image to ECR
67-
uses: kciter/aws-ecr-action@v3
68-
with:
69-
access_key_id: ${{ secrets.INCUBATOR_AWS_ACCESS_KEY_ID }}
70-
secret_access_key: ${{ secrets.INCUBATOR_AWS_SECRET_ACCESS_KEY }}
71-
account_id: ${{ secrets.INCUBATOR_AWS_ACCOUNT_ID }}
72-
repo: ${{ needs.setup_env.outputs.AWS_APPENV }}
73-
region: ${{ env.AWS_REGION }}
74-
tags: latest,${{ needs.setup_env.outputs.IMAGE_TAG }}
75-
dockerfile: ${{ env.DOCKERFILE }}
76-
path: ${{ env.DOCKER_PATH }}
48+
- name: Checkout
49+
uses: actions/checkout@v4
50+
with:
51+
ref: ${{ github.event.inputs.ref }}
52+
- name: Configure AWS credentials
53+
uses: aws-actions/configure-aws-credentials@v4
54+
with:
55+
aws-access-key-id: ${{ secrets.INCUBATOR_AWS_ACCESS_KEY_ID }}
56+
aws-secret-access-key: ${{ secrets.INCUBATOR_AWS_SECRET_ACCESS_KEY }}
57+
aws-region: ${{ env.AWS_REGION }}
58+
- name: Login to Amazon ECR
59+
id: login-ecr
60+
uses: aws-actions/amazon-ecr-login@v2
61+
- name: Set up Docker Buildx
62+
uses: docker/setup-buildx-action@v3
63+
- name: Debug Build Variables
64+
env:
65+
BUILD_SHA: ${{ needs.setup_env.outputs.BUILD_SHA }}
66+
IMAGE_TAG: ${{ needs.setup_env.outputs.IMAGE_TAG }}
67+
run: |
68+
echo "=== Build Debug Information ==="
69+
echo "BUILD_SHA: $BUILD_SHA"
70+
echo "IMAGE_TAG: $IMAGE_TAG"
71+
echo "DOCKERFILE: ${{ env.DOCKERFILE }}"
72+
echo "DOCKER_PATH: ${{ env.DOCKER_PATH }}"
73+
echo "================================"
74+
- name: Build & Push Image to ECR
75+
env:
76+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
77+
ECR_REPOSITORY: ${{ needs.setup_env.outputs.AWS_APPENV }}
78+
IMAGE_TAG: ${{ needs.setup_env.outputs.IMAGE_TAG }}
79+
BUILD_SHA: ${{ needs.setup_env.outputs.BUILD_SHA }}
80+
run: |
81+
docker buildx build \
82+
--platform linux/amd64 \
83+
--cache-from type=gha \
84+
--cache-to type=gha,mode=max \
85+
--push \
86+
--build-arg BUILD_SHA=$BUILD_SHA \
87+
-f ${{ env.DOCKERFILE }} \
88+
-t $ECR_REGISTRY/$ECR_REPOSITORY:latest \
89+
-t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG \
90+
${{ env.DOCKER_PATH }}
7791
deploy:
7892
name: Deploy to AWS ECS
7993
runs-on: ubuntu-latest
8094
needs: [setup_env, build]
8195
steps:
82-
- name: Configure AWS credentials
83-
uses: aws-actions/configure-aws-credentials@v1
84-
with:
85-
aws-access-key-id: ${{ secrets.INCUBATOR_AWS_ACCESS_KEY_ID }}
86-
aws-secret-access-key: ${{ secrets.INCUBATOR_AWS_SECRET_ACCESS_KEY }}
87-
aws-region: ${{ env.AWS_REGION }}
88-
- name: Login to Amazon ECR
89-
id: login-ecr
90-
uses: aws-actions/amazon-ecr-login@v1
91-
- name: Pull Task Definition & write to file
92-
id: aws-task-definition
93-
run: |
94-
aws ecs describe-task-definition \
95-
--task-definition ${{ needs.setup_env.outputs.AWS_APPENV }} \
96-
--query taskDefinition | \
97-
jq 'del(.taskDefinitionArn,.revision,.status,.registeredBy,.registeredAt,.compatibilities,.requiresAttributes)' > task-def.json
98-
- name: Interpolate new Docker Image into Task Definition
99-
id: task-definition
100-
uses: aws-actions/amazon-ecs-render-task-definition@v1
101-
with:
102-
task-definition: task-def.json
103-
container-name: ${{ needs.setup_env.outputs.AWS_APPENV }}
104-
image: ${{ steps.login-ecr.outputs.registry }}/${{ needs.setup_env.outputs.AWS_APPENV }}:${{ needs.setup_env.outputs.IMAGE_TAG }}
105-
- name: Deploy Amazon ECS
106-
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
107-
with:
108-
task-definition: ${{ steps.task-definition.outputs.task-definition }}
109-
service: ${{ needs.setup_env.outputs.AWS_APPENV }}
110-
cluster: ${{ env.AWS_SHARED_CLUSTER }}
111-
wait-for-service-stability: true
112-
wait-for-minutes: 5 minutes
113-
96+
- name: Configure AWS credentials
97+
uses: aws-actions/configure-aws-credentials@v4
98+
with:
99+
aws-access-key-id: ${{ secrets.INCUBATOR_AWS_ACCESS_KEY_ID }}
100+
aws-secret-access-key: ${{ secrets.INCUBATOR_AWS_SECRET_ACCESS_KEY }}
101+
aws-region: ${{ env.AWS_REGION }}
102+
- name: Login to Amazon ECR
103+
id: login-ecr
104+
uses: aws-actions/amazon-ecr-login@v2
105+
- name: Pull Task Definition & write to file
106+
id: aws-task-definition
107+
run: |
108+
aws ecs describe-task-definition \
109+
--task-definition ${{ needs.setup_env.outputs.AWS_APPENV }} \
110+
--query taskDefinition | \
111+
jq 'del(.taskDefinitionArn,.revision,.status,.registeredBy,.registeredAt,.compatibilities,.requiresAttributes)' > task-def.json
112+
- name: Interpolate new Docker Image into Task Definition
113+
id: task-definition
114+
uses: aws-actions/amazon-ecs-render-task-definition@v1
115+
with:
116+
task-definition: task-def.json
117+
container-name: ${{ needs.setup_env.outputs.AWS_APPENV }}
118+
image: ${{ steps.login-ecr.outputs.registry }}/${{ needs.setup_env.outputs.AWS_APPENV }}:${{ needs.setup_env.outputs.IMAGE_TAG }}
119+
- name: Deploy Amazon ECS
120+
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
121+
with:
122+
task-definition: ${{ steps.task-definition.outputs.task-definition }}
123+
service: ${{ needs.setup_env.outputs.AWS_APPENV }}
124+
cluster: ${{ env.AWS_SHARED_CLUSTER }}
125+
wait-for-service-stability: true
126+
wait-for-minutes: 5

backend/Dockerfile.prod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ RUN yarn install --pure-lockfile
77
COPY . .
88

99
FROM node:18.12.0-slim AS api-production
10+
ARG BUILD_SHA
1011
EXPOSE 4000
11-
USER node
1212
WORKDIR /srv/backend
1313
COPY --from=api-builder /srv/backend/node_modules ./node_modules
1414
COPY . .
15+
ENV BUILD_SHA=${BUILD_SHA}
16+
RUN echo "${BUILD_SHA:-unknown}" > BUILD_INFO
17+
USER node
1518
CMD ["npm", "run", "start"]
Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,53 @@
1+
const { execSync } = require('child_process');
2+
const fs = require('fs');
3+
14
const HealthCheckController = {};
25

3-
HealthCheckController.isAlive = (_, res) => {
4-
res.status(200).send("I'm Alive!");
6+
function getBuildInfo() {
7+
// Method 1: BUILD_SHA environment variable (from Docker build arg) - PRIORITY
8+
if (
9+
process.env.BUILD_SHA &&
10+
process.env.BUILD_SHA !== 'undefined' &&
11+
process.env.BUILD_SHA !== ''
12+
) {
13+
return process.env.BUILD_SHA;
14+
}
15+
16+
// Method 2: Check BUILD_INFO file (created during Docker build)
17+
try {
18+
if (fs.existsSync('/srv/backend/BUILD_INFO')) {
19+
const buildInfo = fs.readFileSync('/srv/backend/BUILD_INFO', 'utf8').trim();
20+
if (buildInfo && buildInfo !== 'unknown' && buildInfo !== '') {
21+
return buildInfo;
22+
}
23+
}
24+
} catch {
25+
// BUILD_INFO file not available
26+
}
27+
28+
// Method 3: Try git command (for local development)
29+
try {
30+
const gitSha = execSync('git rev-parse --short HEAD 2>/dev/null', { encoding: 'utf8', shell: true }).trim();
31+
if (gitSha && gitSha !== '' && gitSha !== 'unknown') {
32+
return gitSha;
33+
}
34+
} catch {
35+
// Git not available
36+
}
37+
38+
return 'unknown';
539
}
640

41+
// Cache build info at startup to avoid repeated file I/O and Git calls
42+
const cachedBuildInfo = getBuildInfo();
43+
const buildTimestamp = new Date().toISOString();
44+
45+
HealthCheckController.isAlive = (_, res) => {
46+
res
47+
.status(200)
48+
.send(
49+
`I'm Alive! Build: ${cachedBuildInfo} | Built: ${buildTimestamp} | Checked: ${new Date().toISOString()}`,
50+
);
51+
};
52+
753
module.exports = HealthCheckController;

0 commit comments

Comments
 (0)