diff --git a/.github/workflows/nextjs-prod-CI.yml b/.github/workflows/nextjs-prod-CI.yml new file mode 100644 index 00000000..45584d0d --- /dev/null +++ b/.github/workflows/nextjs-prod-CI.yml @@ -0,0 +1,115 @@ +name: Node.js CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: write + +env: + PROJECT_NAME: dkation + REPOSITORY_NAME: dkation-prod-front + IMAGE_NAME: dkation-prod-fe + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: | + npm ci + npm install -g npm@latest + npm install sharp + + - name: Lint + run: npm run lint + + - name: Build Next.js app + run: npm run build + env: + NEXT_PUBLIC_SERVER_URL: ${{ secrets.NEXT_PUBLIC_SERVER_URL }} + NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }} + NEXTAUTH_URL: ${{ secrets.NEXTAUTH_URL }} + + - name: Get latest tag and create new tag + id: create_tag + run: | + git fetch --tags + latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") + + while true; do + IFS='.' read -ra ADDR <<< "${latest_tag#v}" + major="${ADDR[0]}" + minor="${ADDR[1]}" + patch="${ADDR[2]}" + new_patch=$((patch + 1)) + new_tag="v$major.$minor.$new_patch" + + if git rev-parse $new_tag >/dev/null 2>&1; then + echo "Tag $new_tag already exists, incrementing..." + latest_tag=$new_tag + else + echo "NEW_TAG=$new_tag" >> $GITHUB_OUTPUT + break + fi + done + + - name: Create and push new tag + env: + PAT: ${{ secrets.PAT }} + run: | + git config user.name github-actions + git config user.email github-actions@github.com + git tag ${{ steps.create_tag.outputs.NEW_TAG }} + git push https://$PAT@github.com/${{ github.repository }}.git ${{ steps.create_tag.outputs.NEW_TAG }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to KCR + uses: docker/login-action@v2 + with: + registry: ${{ env.PROJECT_NAME }}.kr-central-2.kcr.dev + username: ${{ secrets.ACCESS_KEY }} + password: ${{ secrets.ACCESS_SECRET_KEY }} + + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + context: . + push: true + tags: | + ${{ env.PROJECT_NAME }}.kr-central-2.kcr.dev/${{ env.REPOSITORY_NAME }}/${{ env.IMAGE_NAME }}:${{ steps.create_tag.outputs.NEW_TAG }} + ${{ env.PROJECT_NAME }}.kr-central-2.kcr.dev/${{ env.REPOSITORY_NAME }}/${{ env.IMAGE_NAME }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + NEXT_PUBLIC_SERVER_URL=${{ secrets.NEXT_PUBLIC_SERVER_URL }} + NEXTAUTH_SECRET=${{ secrets.NEXTAUTH_SECRET }} + NEXTAUTH_URL=${{ secrets.NEXTAUTH_URL }} + + - name: Create Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.create_tag.outputs.NEW_TAG }} + release_name: Release ${{ steps.create_tag.outputs.NEW_TAG }} + draft: false + prerelease: false \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index f4b20992..0262049a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,18 @@ -# Base image +# Build stage FROM node:18-alpine AS builder +ARG NEXT_PUBLIC_SERVER_URL +ARG NEXTAUTH_SECRET +ARG NEXTAUTH_URL + +ENV NEXT_PUBLIC_SERVER_URL=${NEXT_PUBLIC_SERVER_URL} +ENV NEXTAUTH_SECRET=${NEXTAUTH_SECRET} +ENV NEXTAUTH_URL=${NEXTAUTH_URL} + # Set working directory WORKDIR /app -# Copy package.json and package-lock.json +# Copy package files COPY package.json package-lock.json* ./ # Install dependencies @@ -13,29 +21,43 @@ RUN npm ci # Copy the rest of the application code COPY . . +# Install sharp for improved image optimization +RUN npm install sharp + # Build the Next.js application RUN npm run build -# Start a new stage for a smaller production image -FROM node:18-alpine +# Production stage +FROM node:18-alpine AS runner +# Set working directory WORKDIR /app -# Copy package.json and package-lock.json -COPY package.json package-lock.json* ./ +# Set node environment to production +ENV NODE_ENV=production -# Install only production dependencies -RUN npm ci --only=production +# Add a non-root user +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs -# Copy the built app from the previous stage -COPY --from=builder /app/.next ./.next +# Copy necessary files from build stage +COPY --from=builder /app/next.config.mjs ./ COPY --from=builder /app/public ./public +COPY --from=builder /app/package.json ./package.json + +# Copy the built app +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +# Set the correct permission for prerender cache +RUN mkdir -p .next +RUN chown nextjs:nodejs .next -# Copy next.config.mjs -COPY --from=builder /app/next.config.mjs ./next.config.mjs +# Switch to non-root user +USER nextjs # Expose the port the app runs on EXPOSE 3000 # Start the application -CMD ["npm", "start", "--", "-p", "3000"] \ No newline at end of file +CMD ["node", "server.js"] \ No newline at end of file diff --git a/next.config.mjs b/next.config.mjs index a19af1b6..aee44e44 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - + output: 'standalone', // Add this line reactStrictMode: false, redirects: async () => { return [