diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..4ed881a1b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.dockerignore +.git +.next +.turbo +dist +docker +Dockerfile +node_modules +npm-debug.log +README.md diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml new file mode 100644 index 000000000..31eda494d --- /dev/null +++ b/.github/workflows/docker.yaml @@ -0,0 +1,58 @@ +name: Docker +on: + push: + tags: + - "v*" + pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +permissions: + contents: read + packages: write + id-token: write +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta + id: docker_meta + uses: docker/metadata-action@v4 + with: + images: | + name=ghcr.io/cartesi/rollups-explorer + name=docker.io/cartesi/rollups-explorer,enable=${{ startsWith(github.ref, 'refs/tags/v') }} + tags: | + type=semver,pattern={{version}} + type=ref,event=branch + type=ref,event=pr + + - name: Login to Docker Hub + uses: docker/login-action@v2 + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: depot/setup-action@v1 + + - name: Build and push docker image + id: docker_build + uses: depot/bake-action@v1 + with: + files: | + ./docker-bake.hcl + ${{ steps.docker_meta.outputs.bake-file }} + ./docker-bake.platforms.hcl + push: true + project: ${{ vars.DEPOT_PROJECT }} diff --git a/.vscode/settings.json b/.vscode/settings.json index 94a8a7271..02499dfe8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,8 @@ "editor.codeActionsOnSave": { "source.fixAll": true, "source.organizeImports": true + }, + "[terraform]": { + "editor.defaultFormatter": "hashicorp.terraform" } -} \ No newline at end of file +} diff --git a/apps/web/.env.localhost b/apps/web/.env.localhost index 38ba698c0..f9029c9a8 100644 --- a/apps/web/.env.localhost +++ b/apps/web/.env.localhost @@ -1,2 +1,2 @@ NEXT_PUBLIC_CHAIN_ID=31337 -NEXT_PUBLIC_EXPLORER_API_URL="http://127.0.0.1:8545" +NEXT_PUBLIC_EXPLORER_API_URL="http://127.0.0.1:4350/graphql" diff --git a/apps/web/.env.sunodo b/apps/web/.env.sunodo new file mode 100644 index 000000000..4029b6f7e --- /dev/null +++ b/apps/web/.env.sunodo @@ -0,0 +1,3 @@ +NEXT_PUBLIC_CHAIN_ID=31337 +NEXT_PUBLIC_EXPLORER_API_URL="http://squid_api:4350/graphql" +BASE_PATH="/explorer" diff --git a/apps/web/codegen.ts b/apps/web/codegen.ts index 369ae754d..1839be2f3 100644 --- a/apps/web/codegen.ts +++ b/apps/web/codegen.ts @@ -1,11 +1,8 @@ import type { CodegenConfig } from "@graphql-codegen/cli"; -const schema = process.env.NEXT_PUBLIC_EXPLORER_API_URL; - -if (!schema) - throw new Error( - "NEXT_PUBLIC_EXPLORER_API_URL environment variable is required for GraphQL code generation.", - ); +const schema = "https://squid.subsquid.io/cartesi-rollups-mainnet/graphql"; +// const schema = "https://squid.subsquid.io/cartesi-rollups-sepolia/graphql"; +// const schema = "http://127.0.0.1:4350/graphql"; const plugins = [ { diff --git a/apps/web/next.config.js b/apps/web/next.config.js index dab08b83c..a6f7c79f7 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -2,6 +2,8 @@ const nextConfig = { reactStrictMode: true, swcMinify: true, + output: "standalone", + basePath: process.env.BASE_PATH || "", }; module.exports = nextConfig; diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 000000000..5d8fbe5d9 --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,11 @@ +target "docker-metadata-action" {} +target "docker-platforms" {} + +target "default" { + inherits = ["docker-metadata-action", "docker-platforms"] + dockerfile = "docker/Dockerfile" + context = "." + args = { + "ENVIRONMENT" = "sunodo" + } +} diff --git a/docker-bake.override.hcl b/docker-bake.override.hcl new file mode 100644 index 000000000..9b89c976b --- /dev/null +++ b/docker-bake.override.hcl @@ -0,0 +1,3 @@ +target "default" { + tags = ["cartesi/rollups-explorer:devel"] +} diff --git a/docker-bake.platforms.hcl b/docker-bake.platforms.hcl new file mode 100644 index 000000000..7fe613193 --- /dev/null +++ b/docker-bake.platforms.hcl @@ -0,0 +1,6 @@ +target "docker-platforms" { + platforms = [ + "linux/amd64", + "linux/arm64" + ] +} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 000000000..32bfd2d6d --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,53 @@ +FROM node:20-alpine as base + +FROM base as builder +RUN apk add --no-cache libc6-compat +RUN apk update + +WORKDIR /app +RUN yarn global add turbo +COPY . . +RUN turbo prune --scope=web --docker + +# Add lockfile and package.json's of isolated subworkspace +FROM base AS installer +RUN apk add --no-cache libc6-compat +RUN apk update +WORKDIR /app + +# First install the dependencies (as they change less often) +COPY .gitignore .gitignore +COPY --from=builder /app/out/json/ . +COPY --from=builder /app/out/yarn.lock ./yarn.lock +RUN yarn install + +# Build the project +COPY --from=builder /app/out/full/ . +ARG ENVIRONMENT=localhost +COPY --from=builder /app/out/full/apps/web/.env.${ENVIRONMENT} ./apps/web/.env +RUN yarn build --filter=web + +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production + +# Don't run production as root +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +#COPY --from=installer /app/apps/web/public ./public +COPY --from=installer /app/apps/web/next.config.js . +COPY --from=installer /app/apps/web/package.json . + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/standalone ./ +COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static + +USER nextjs +EXPOSE 3000 +ENV PORT 3000 +ENV HOSTNAME 0.0.0.0 + +CMD ["node", "apps/web/server.js"] diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml new file mode 100644 index 000000000..43fd5ce3f --- /dev/null +++ b/docker/docker-compose.yaml @@ -0,0 +1,14 @@ +version: "3.9" + +services: + proxy: + image: traefik:v2.10 + ports: + - 8080:8080 + - 8088:8088 + volumes: + - ./traefik:/etc/traefik + explorer: + image: cartesi/rollups-explorer:devel + expose: + - 3000 diff --git a/docker/traefik/conf.d/explorer.yaml b/docker/traefik/conf.d/explorer.yaml new file mode 100644 index 000000000..731f723ea --- /dev/null +++ b/docker/traefik/conf.d/explorer.yaml @@ -0,0 +1,10 @@ +http: + routers: + explorer: + rule: "PathPrefix(`/explorer`)" + service: explorer + services: + explorer: + loadBalancer: + servers: + - url: "http://explorer:3000" diff --git a/docker/traefik/traefik.yaml b/docker/traefik/traefik.yaml new file mode 100644 index 000000000..e33c7536f --- /dev/null +++ b/docker/traefik/traefik.yaml @@ -0,0 +1,11 @@ +api: + dashboard: true + insecure: true +entryPoints: + web: + address: ":8080" + traefik: + address: ":8088" +providers: + file: + directory: /etc/traefik/conf.d diff --git a/turbo.json b/turbo.json index 331cc3bc6..1a0c2656c 100644 --- a/turbo.json +++ b/turbo.json @@ -1,6 +1,10 @@ { "$schema": "https://turbo.build/schema.json", - "globalEnv": ["NEXT_PUBLIC_CHAIN_ID", "NEXT_PUBLIC_EXPLORER_API_URL"], + "globalEnv": [ + "BASE_PATH", + "NEXT_PUBLIC_CHAIN_ID", + "NEXT_PUBLIC_EXPLORER_API_URL" + ], "pipeline": { "build": { "dependsOn": ["^build", "codegen"],