diff --git a/.github/workflows/actions/setup-aws-ecr-login/action.yml b/.github/workflows/actions/setup-aws-ecr-login/action.yml new file mode 100644 index 0000000..8718421 --- /dev/null +++ b/.github/workflows/actions/setup-aws-ecr-login/action.yml @@ -0,0 +1,29 @@ +name: "Setup AWS and ECR Login" +description: "Configures AWS credentials and logs into Amazon ECR" + +inputs: + aws-region: + description: "AWS Region" + required: true + aws-access-key-id: + description: "AWS Access Key ID" + required: true + aws-secret-access-key: + description: "AWS Secret Access Key" + required: true + +runs: + using: "composite" + steps: + - name: Set AWS Credentials + shell: bash + run: | + echo "AWS_ACCESS_KEY_ID=${{ inputs.aws-access-key-id }}" >> $GITHUB_ENV + echo "AWS_SECRET_ACCESS_KEY=${{ inputs.aws-secret-access-key }}" >> $GITHUB_ENV + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ${{ inputs.aws-region }} + + - name: Login to Amazon ECR + uses: aws-actions/amazon-ecr-login@v2 \ No newline at end of file diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index e996b0e..475b01a 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -8,7 +8,9 @@ env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} DOCKERFILE: Dockerfile - HUSKY: 0 + # Require for ECS deployment + #ENVIRONMENT: ${{ (github.ref_name == 'develop' && 'staging') || (github.ref_name == 'master' && 'production') }} + #ECR_REGISTRY: ${{ vars.DOCKER_REGISTRY }} jobs: build: @@ -22,6 +24,22 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Read Node version from .nvmrc + id: node_version + run: echo "NODE_VER=$(cat .nvmrc)" >> $GITHUB_OUTPUT + + - name: Install pnpm + uses: pnpm/action-setup@v2 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ steps.node_version.outputs.NODE_VER }} + cache: 'pnpm' + + - name: Security Audit + run: pnpm audit --audit-level high + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -31,6 +49,14 @@ jobs: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + # Require for ECS deployment + # - name: Setup AWS and Login to ECR + # uses: ./.github/actions/setup-aws-ecr-login + # with: + # aws-region: ${{ vars.AWS_REGION }} + # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - name: Metadata Extraction for Main Image id: meta_main @@ -39,6 +65,16 @@ jobs: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=raw,value=${{ github.ref_name }} + + # Require for ECS deployment + # - name: Metadata Extraction for Main Image + # id: meta_main + # uses: docker/metadata-action@v5 + # with: + # images: ${{ env.ECR_REGISTRY }}/${{ vars.PROJECT_NAME }}-${{ env.ENVIRONMENT }}-frontend + # tags: | + # # dynamically set the branch name with a prefix as a custom tag. + # type=raw,value=${{ (github.ref_name == 'develop' && 'staging') || (github.ref_name == 'master' && 'production') }} - name: Build and Push Main Image uses: docker/build-push-action@v6 @@ -48,11 +84,14 @@ jobs: file: ${{ env.DOCKERFILE }} tags: ${{ steps.meta_main.outputs.tags }} labels: ${{ steps.meta_main.outputs.labels }} + build-args: | + NODE_VERSION=${{ steps.node_version.outputs.NODE_VER }} cache-from: type=gha cache-to: type=gha,mode=max secrets: | "next_env_variables=${{ secrets.NEXT_ENV_VARIABLES}}" - + + # Ansible Deploy deploy: environment: ${{ github.ref_name == 'master' && 'production' || 'staging'}} runs-on: ubuntu-latest @@ -74,4 +113,21 @@ jobs: cd $PROJECT_PATH set -euxo pipefail git pull - ansible-playbook -i inventory/${{ github.ref_name == 'master' && 'production' || 'staging'}} site.yml --tags deploy --extra-vars "services_to_start=['front'] docker_compose_project_github_token=${{ secrets.GITHUB_TOKEN }} docker_compose_project_github_actor=${{ github.actor }}" \ No newline at end of file + ansible-playbook -i inventory/${{ github.ref_name == 'master' && 'production' || 'staging'}} site.yml --tags deploy --extra-vars "services_to_start=['front'] docker_compose_project_github_token=${{ secrets.GITHUB_TOKEN }} docker_compose_project_github_actor=${{ github.actor }}" + + # Require for ECS deployment + # deploy: + # environment: ${{ (github.ref_name == 'develop' && 'staging') || (github.ref_name == 'master' && 'production') }} + # runs-on: ubuntu-latest + # needs: build + # steps: + # - name: Deploy to ${{ (github.ref_name == 'develop' && 'staging') || (github.ref_name == 'master' && 'production') }} + # env: + # ENVIRONMENT: ${{ (github.ref_name == 'develop' && 'staging') || (github.ref_name == 'master' && 'production') }} + # AWS_REGION: ${{ vars.AWS_REGION }} + # AWS_ECS_CLUSTER: ${{ vars.AWS_ECS_CLUSTER }} + # AWS_ECS_SERVICE: ${{ vars.AWS_ECS_SERVICE }} + # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + # run: | + # aws ecs update-service --cluster $AWS_ECS_CLUSTER --service $AWS_ECS_SERVICE --force-new-deployment --region $AWS_REGION \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 575b304..7d9f648 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,62 +1,47 @@ -FROM node:18-alpine AS base +ARG NODE_VERSION=18-alpine + +FROM node:${NODE_VERSION} AS base RUN corepack enable -# Install dependencies only when needed FROM base AS deps -# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. RUN apk add --no-cache libc6-compat WORKDIR /app -# Install dependencies based on the preferred package manager COPY package.json pnpm-lock.yaml ./ -RUN pnpm install +RUN pnpm install --frozen-lockfile --ignore-scripts -# Rebuild the source code only when needed FROM base AS builder WORKDIR /app + COPY --from=deps /app/node_modules ./node_modules COPY . . -# Next.js collects completely anonymous telemetry data about general usage. -# Learn more here: https://nextjs.org/telemetry -# Uncomment the following line in case you want to disable telemetry during the build. -# ENV NEXT_TELEMETRY_DISABLED 1 - RUN --mount=type=secret,id=next_env_variables \ cat /run/secrets/next_env_variables > .env.local -RUN pnpm build +RUN pnpm ioc-generate -# If using npm comment out above and use below instead -# RUN npm run build +RUN pnpm build -# Production image, copy all the files and run next FROM base AS runner WORKDIR /app -ENV NODE_ENV production -# Uncomment the following line in case you want to disable telemetry during runtime. -# ENV NEXT_TELEMETRY_DISABLED 1 +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public - -# Set the correct permission for prerender cache -RUN mkdir .next -RUN chown nextjs:nodejs .next - -# Automatically leverage output traces to reduce image size -# https://nextjs.org/docs/advanced-features/output-file-tracing COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +RUN chown -R nextjs:nodejs .next + USER nextjs EXPOSE 3000 +ENV PORT=3000 -ENV PORT 3000 - -CMD ["node", "server.js"] +CMD ["node", "server.js"] \ No newline at end of file diff --git a/next.config.js b/next.config.js index 06ad6ed..961187a 100644 --- a/next.config.js +++ b/next.config.js @@ -21,6 +21,7 @@ const { const apiDomain = NODE_ENV !== "production" ? "next_base.dev.mrmilu.com" : NEXT_PUBLIC_API_URL?.replace("https://", "") ?? ""; const nextConfig = { + output: "standalone", eslint: { dirs: ["app", "src"] },