diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a768ef9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,38 @@ +node_modules +build +.cache +dist + +# Git +.git +.gitignore + +# Environment +.env +.env.local +.env.*.local + +# IDE +.vscode +.idea +*.sw? + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +npm-debug.log* + +# CI/CD +.github + +# Docs +docs +*.md +!README.md + +# Database local files +*.db +*.db-journal diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8486e41 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,86 @@ +name: CI - Build & Push Docker Image + +on: + push: + branches: [main,docker_deployment] + pull_request: + branches: [main] + +env: + DOCKERHUB_REPO: sunilagwl5/template-viber + +jobs: + # lint-and-typecheck: + # name: Lint & Typecheck + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + + # - uses: oven-sh/setup-bun@v2 + # with: + # bun-version: "latest" + + # - name: Install dependencies + # run: bun install --frozen-lockfile + + # - name: Lint + # run: bun run lint + + # - name: Typecheck + # run: bun run typecheck + + # test: + # name: Unit Tests + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + + # - uses: oven-sh/setup-bun@v2 + # with: + # bun-version: "latest" + + # - name: Install dependencies + # run: bun install --frozen-lockfile + + # - name: Run tests + # run: bun run test + + docker: + name: Build & Push Docker Image + runs-on: ubuntu-latest + # needs: [lint-and-typecheck, test] + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.DOCKERHUB_REPO }} + tags: | + type=sha,prefix= + type=raw,value=latest,enable={{is_default_branch}} + type=ref,event=pr + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64,linux/arm64 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7744cdd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,54 @@ +# ============================================================ +# Stage 1: Install dependencies +# ============================================================ +FROM oven/bun:1-alpine AS deps + +WORKDIR /app + +COPY package.json bun.lock ./ +RUN bun install --frozen-lockfile + +# ============================================================ +# Stage 2: Build the application +# ============================================================ +FROM oven/bun:1-alpine AS build + +WORKDIR /app + +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +ENV NODE_ENV=production +ENV VITE_CJS_IGNORE_WARNING=true + +RUN bun run build + +# Prune dev dependencies after build +RUN bun install --frozen-lockfile --production && \ + rm -rf /app/.cache + +# ============================================================ +# Stage 3: Production runtime +# ============================================================ +FROM node:20-alpine AS production + +WORKDIR /app + +ENV NODE_ENV=production +ENV PORT=5173 + +# Add non-root user for security +RUN addgroup --system --gid 1001 remix && \ + adduser --system --uid 1001 remix + +# Copy only what's needed for production +COPY --from=build /app/build ./build +COPY --from=build /app/node_modules ./node_modules +COPY --from=build /app/package.json ./package.json +COPY --from=build /app/public ./public + +USER remix + +EXPOSE 5173 + +CMD ["npm", "run", "start"]