Skip to content

Commit 0be92c3

Browse files
committed
feat: add aws workflow and build container
add a github actions workflow which automates aws deployment through ECS Refs: #48
1 parent 98873c1 commit 0be92c3

5 files changed

Lines changed: 265 additions & 1 deletion

File tree

.github/workflows/aws.yml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# This workflow will build and push a new container image to Amazon ECR,
2+
# and then will deploy a new task definition to Amazon ECS, when there is a push to the "main" branch.
3+
#
4+
# To use this workflow, you will need to complete the following set-up steps:
5+
#
6+
# 1. Create an ECR repository to store your images.
7+
# For example: `aws ecr create-repository --repository-name my-ecr-repo --region us-east-2`.
8+
# Replace the value of the `ECR_REPOSITORY` environment variable in the workflow below with your repository's name.
9+
# Replace the value of the `AWS_REGION` environment variable in the workflow below with your repository's region.
10+
#
11+
# 2. Create an ECS task definition, an ECS cluster, and an ECS service.
12+
# For example, follow the Getting Started guide on the ECS console:
13+
# https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun
14+
# Replace the value of the `ECS_SERVICE` environment variable in the workflow below with the name you set for the Amazon ECS service.
15+
# Replace the value of the `ECS_CLUSTER` environment variable in the workflow below with the name you set for the cluster.
16+
#
17+
# 3. Store your ECS task definition as a JSON file in your repository.
18+
# The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`.
19+
# Replace the value of the `ECS_TASK_DEFINITION` environment variable in the workflow below with the path to the JSON file.
20+
# Replace the value of the `CONTAINER_NAME` environment variable in the workflow below with the name of the container
21+
# in the `containerDefinitions` section of the task definition.
22+
#
23+
# 4. Store an IAM user access key in GitHub Actions secrets named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
24+
# See the documentation for each action used below for the recommended IAM policies for this IAM user,
25+
# and best practices on handling the access key credentials.
26+
27+
name: Deploy to Amazon ECS
28+
29+
on:
30+
push:
31+
branches: [ "main", "backend_server" ]
32+
33+
env:
34+
AWS_REGION: eu-north-1 # set this to your preferred AWS region, e.g. us-west-1
35+
ECR_REPOSITORY: lab-repository # set this to your Amazon ECR repository name
36+
ECS_SERVICE: LabManager-task-service-first # set this to your Amazon ECS service name
37+
ECS_CLUSTER: excited-fish # set this to your Amazon ECS cluster name
38+
ECS_TASK_DEFINITION: ../../labman/LabManager-task-definition.json # set this to the path to your Amazon ECS task definition
39+
# file, e.g. .aws/task-definition.json
40+
CONTAINER_NAME: nextjs-lab # set this to the name of the container in the
41+
# containerDefinitions section of your task definition
42+
DATABASE_URL: ${{secrets.DATABASE_URL}}
43+
44+
permissions:
45+
contents: read
46+
id-token: write
47+
48+
jobs:
49+
deploy:
50+
name: Deploy
51+
runs-on: ubuntu-latest
52+
environment: production
53+
54+
steps:
55+
- name: Checkout
56+
uses: actions/checkout@v4
57+
58+
#- name: Configure AWS credentials
59+
# uses: aws-actions/configure-aws-credentials@v1
60+
#with:
61+
# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
62+
#aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
63+
#aws-region: ${{ env.AWS_REGION }}
64+
- name: Configure AWS credentials
65+
uses: aws-actions/configure-aws-credentials@main
66+
with:
67+
audience: sts.amazonaws.com
68+
aws-region: ${{ env.AWS_REGION }}
69+
role-to-assume: arn:aws:iam::861353196312:role/ghRole
70+
71+
- name: Login to Amazon ECR
72+
id: login-ecr
73+
uses: aws-actions/amazon-ecr-login@v1
74+
75+
- name: Build, tag, and push image to Amazon ECR
76+
id: build-image
77+
env:
78+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
79+
IMAGE_TAG: ${{ github.sha }}
80+
run: |
81+
# Build a docker container and
82+
# push it to ECR so that it can
83+
# be deployed to ECS.
84+
docker build --build-arg DATABASE_URL="$DATABASE_URL" -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
85+
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
86+
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
87+
88+
- name: Fill in the new image ID in the Amazon ECS task definition
89+
id: task-def
90+
uses: aws-actions/amazon-ecs-render-task-definition@v1
91+
with:
92+
task-definition: ${{ env.ECS_TASK_DEFINITION }}
93+
container-name: ${{ env.CONTAINER_NAME }}
94+
image: ${{ steps.build-image.outputs.image }}
95+
96+
- name: Deploy Amazon ECS task definition
97+
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
98+
with:
99+
task-definition: ${{ steps.task-def.outputs.task-definition }}
100+
service: ${{ env.ECS_SERVICE }}
101+
cluster: ${{ env.ECS_CLUSTER }}
102+
wait-for-service-stability: true

labman/Dockerfile

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# syntax=docker.io/docker/dockerfile:1
2+
3+
FROM node:20-alpine AS base
4+
5+
# Install dependencies only when needed
6+
FROM base AS deps
7+
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
8+
RUN apk add --no-cache libc6-compat
9+
WORKDIR /app
10+
11+
# Install dependencies based on the preferred package manager
12+
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
13+
RUN \
14+
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
15+
elif [ -f package-lock.json ]; then npm ci; \
16+
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
17+
else echo "Lockfile not found." && exit 1; \
18+
fi
19+
20+
21+
# Rebuild the source code only when needed
22+
FROM base AS builder
23+
WORKDIR /app
24+
COPY --from=deps /app/node_modules ./node_modules
25+
COPY . .
26+
27+
# Next.js collects completely anonymous telemetry data about general usage.
28+
# Learn more here: https://nextjs.org/telemetry
29+
# Uncomment the following line in case you want to disable telemetry during the build.
30+
# ENV NEXT_TELEMETRY_DISABLED=1
31+
32+
ARG DATABASE_URL
33+
ENV DATABASE_URL=${DATABASE_URL}
34+
35+
RUN npx prisma generate
36+
37+
RUN \
38+
if [ -f yarn.lock ]; then yarn run build; \
39+
elif [ -f package-lock.json ]; then npm run build; \
40+
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
41+
else echo "Lockfile not found." && exit 1; \
42+
fi
43+
44+
# Production image, copy all the files and run next
45+
FROM base AS runner
46+
WORKDIR /app
47+
48+
49+
# Uncomment the following line in case you want to disable telemetry during runtime.
50+
# ENV NEXT_TELEMETRY_DISABLED=1
51+
52+
RUN addgroup --system --gid 1001 nodejs
53+
RUN adduser --system --uid 1001 nextjs
54+
55+
COPY --from=builder /app/public ./public
56+
57+
# Automatically leverage output traces to reduce image size
58+
# https://nextjs.org/docs/advanced-features/output-file-tracing
59+
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
60+
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
61+
62+
USER nextjs
63+
64+
EXPOSE 3000
65+
66+
ENV PORT=3000
67+
68+
# server.js is created by next build from the standalone output
69+
# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output
70+
ENV HOSTNAME="0.0.0.0"
71+
CMD ["node", "server.js"]
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
{
2+
"taskDefinitionArn": "arn:aws:ecs:eu-north-1:861353196312:task-definition/LabManager-task:1",
3+
"containerDefinitions": [
4+
{
5+
"name": "nextjs-lab",
6+
"image": "861353196312.dkr.ecr.eu-north-1.amazonaws.com/lab-repository@sha256:e7cdbf6f8318d5c7a55d534faa467df83a3dd9f9e9663068abef74fd19ff41d1",
7+
"cpu": 0,
8+
"portMappings": [
9+
{
10+
"name": "main",
11+
"containerPort": 3000,
12+
"hostPort": 3000,
13+
"protocol": "tcp",
14+
"appProtocol": "http"
15+
}
16+
],
17+
"essential": true,
18+
"environment": [],
19+
"environmentFiles": [],
20+
"mountPoints": [],
21+
"volumesFrom": [],
22+
"ulimits": [],
23+
"logConfiguration": {
24+
"logDriver": "awslogs",
25+
"options": {
26+
"awslogs-group": "/ecs/LabManager-task",
27+
"awslogs-create-group": "true",
28+
"awslogs-region": "eu-north-1",
29+
"awslogs-stream-prefix": "ecs"
30+
},
31+
"secretOptions": []
32+
},
33+
"systemControls": []
34+
}
35+
],
36+
"family": "LabManager-task",
37+
"executionRoleArn": "arn:aws:iam::861353196312:role/ecsTaskExecutionRole",
38+
"networkMode": "awsvpc",
39+
"revision": 1,
40+
"volumes": [],
41+
"status": "ACTIVE",
42+
"requiresAttributes": [
43+
{
44+
"name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
45+
},
46+
{
47+
"name": "ecs.capability.execution-role-awslogs"
48+
},
49+
{
50+
"name": "com.amazonaws.ecs.capability.ecr-auth"
51+
},
52+
{
53+
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
54+
},
55+
{
56+
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.21"
57+
},
58+
{
59+
"name": "ecs.capability.execution-role-ecr-pull"
60+
},
61+
{
62+
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
63+
},
64+
{
65+
"name": "ecs.capability.task-eni"
66+
},
67+
{
68+
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
69+
}
70+
],
71+
"placementConstraints": [],
72+
"compatibilities": [
73+
"EC2",
74+
"FARGATE",
75+
"MANAGED_INSTANCES"
76+
],
77+
"requiresCompatibilities": [
78+
"FARGATE"
79+
],
80+
"cpu": "1024",
81+
"memory": "3072",
82+
"runtimePlatform": {
83+
"cpuArchitecture": "X86_64",
84+
"operatingSystemFamily": "LINUX"
85+
},
86+
"registeredAt": "2026-01-29T14:16:22.647Z",
87+
"registeredBy": "arn:aws:iam::861353196312:root",
88+
"enableFaultInjection": false,
89+
"tags": []
90+
}

labman/next.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { NextConfig } from "next";
22

33
const nextConfig: NextConfig = {
44
/* config options here */
5+
output: "standalone",
56
};
67

78
export default nextConfig;

labman/prisma/schema.prisma

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
generator client {
88
provider = "prisma-client-js"
9-
binaryTargets = ["native", "debian-openssl-3.0.x"]
9+
binaryTargets = ["native", "debian-openssl-3.0.x", "linux-musl-openssl-3.0.x"]
1010
output = "../src/generated/prisma"
1111
}
1212

0 commit comments

Comments
 (0)