From 5dd37134755c1802b622d7290587ab9b3b5286a4 Mon Sep 17 00:00:00 2001 From: Mythie Date: Sat, 8 Apr 2023 23:09:57 +1000 Subject: [PATCH] feat: add docker support and docker-compose quickstart Add support for production container builds using the provided `Dockerfile` and `build.sh` script. This can later be used with actions to automatically publish to the provided docker registry. Additionally, support an accelerated developer quickstart using `docker-compose`. Developers can now run the `dx` npm command to quickly spin up a database and mail server. --- .dockerignore | 38 ++++++++++++++++++++++++++ .env.example | 11 +++++++- README.md | 32 ++++++++++++++++++++++ docker/Dockerfile | 50 ++++++++++++++++++++++++++++++++++ docker/build.sh | 28 +++++++++++++++++++ docker/compose-entrypoint.sh | 12 ++++++++ docker/compose-without-app.yml | 16 +++++++++++ docker/compose.yml | 40 +++++++++++++++++++++++++++ package.json | 7 +++-- scripts/dx.sh | 42 ++++++++++++++++++++++++++++ 10 files changed, 272 insertions(+), 4 deletions(-) create mode 100644 .dockerignore create mode 100644 docker/Dockerfile create mode 100755 docker/build.sh create mode 100755 docker/compose-entrypoint.sh create mode 100644 docker/compose-without-app.yml create mode 100644 docker/compose.yml create mode 100755 scripts/dx.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..636f6f165 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,38 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +**/node_modules +**/.pnp +**.pnp.js + +# testing +**/coverage + +# next.js +**/.next/ +**/out/ + +# production +**/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts +.env +.env.example diff --git a/.env.example b/.env.example index 4c7dcecb5..9bca5df28 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,9 @@ # Database # Option 1: You can use the provided remote test database, courtesy of the documenso team: postgres://documenso_test_user:GnmLG14u12sd9zHsd4vVWwP40WneFJMo@dpg-cf2hljh4reb5o45oqpq0-a.oregon-postgres.render.com/documenso_test_e2i3 # Option 2: Set up a local Postgres SQL instance (RECOMMENDED) +# Option 3: Use the provided dx setup (RECOMMENDED) +# => postgres://documenso:password@127.0.0.1:5432/documenso +# # ⚠ WARNING: The test database can be resetted or taken offline at any point. # ⚠ WARNING: Please be aware that nothing written to the test databae is private. DATABASE_URL='' @@ -20,6 +23,12 @@ SENDGRID_API_KEY='' # SMTP # Set SMTP credentials to use SMTP instead of the Sendgrid API. +# If you're using the dx setup you can use the following values: +# +# SMTP_MAIL_HOST='127.0.0.1' +# SMTP_MAIL_PORT='2500' +# SMTP_MAIL_USER='documenso' +# SMTP_MAIL_PASSWORD='documenso' SMTP_MAIL_HOST='' SMTP_MAIL_PORT='' SMTP_MAIL_USER='' @@ -30,4 +39,4 @@ MAIL_FROM='documenso@localhost.com' #FEATURE FLAGS # Allow users to register via the /signup page. Otherwise they will be redirect to the home page. -ALLOW_SIGNUP=true \ No newline at end of file +ALLOW_SIGNUP=true diff --git a/README.md b/README.md index d37fbf5b1..d162bf9e8 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,29 @@ To run Documenso locally you need - Node Package Manger NPM - included in Node.js - [PostgreSQL (local or remote)](https://www.postgresql.org/download/) +## Developer Quickstart + +> **Note**: This is a quickstart for developers. It assumes that you have both [docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/) installed on your machine. + +Want to get up and running quickly? Follow these steps: + +- [Clone the repository](https://help.github.com/articles/cloning-a-repository/) it to your local device. + + ```sh + git clone https://github.com/documenso/documenso + ``` + +- Set up your .env file using the recommendations in the .env.example file. +- Run `npm run dx` in the root directory + - This will spin up a postgres database and inbucket mail server in docker containers. +- Run `npm run dev` in the root directory + +That's it! You should now be able to access the app at http://localhost:3000 + +Incoming mail will be available at http://localhost:9000 + +Your database will also be available on port `5432`. You can connect to it using your favorite database client. + ## Developer Setup Follow these steps to setup documenso on you local machnine: @@ -153,6 +176,15 @@ For the digital signature of you documents you need a signign certificate in .p1 4. You will be prompted to enter a password for the p12 file. Choose a strong password and remember it, as you will need it to use the certificate (**can be empty for dev certificates**) 5. Place the certificate /apps/web/ressource/certificate.p12 +# Docker + +> We are still working on the publishing of docker images, in the meantime you can follow the steps below to create a production ready docker image. + +Want to create a production ready docker image? Follow these steps: + +- Run `./docker/build.sh` in the root directory. +- Publish the image to your docker registry of choice. + # Deploying - Coming Soon™ - Docker support diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 000000000..5b19b2726 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,50 @@ +FROM node:18-alpine AS base + +# Install dependencies only when needed +FROM base AS production_deps +WORKDIR /app + +# 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 + +# Copy our current monorepo +COPY . . + +RUN npm ci --production + +# Install dependencies only when needed +FROM base AS builder +WORKDIR /app + +# 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 + +# Copy our current monorepo +COPY . . + +RUN npm ci + +RUN npm run build --workspaces + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production +ENV NEXT_TELEMETRY_DISABLED 1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=production_deps --chown=nextjs:nodejs /app/node_modules ./node_modules +COPY --from=production_deps --chown=nextjs:nodejs /app/package-lock.json ./package-lock.json + +COPY --from=builder --chown=nextjs:nodejs /app/apps/web/package.json ./package.json +COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next ./.next + +EXPOSE 3000 + +ENV PORT 3000 + +CMD ["npm", "run", "start"] \ No newline at end of file diff --git a/docker/build.sh b/docker/build.sh new file mode 100755 index 000000000..9a1ed88fb --- /dev/null +++ b/docker/build.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +command -v docker >/dev/null 2>&1 || { + echo "Docker is not running. Please start Docker and try again." + exit 1 +} + +command -v jq >/dev/null 2>&1 || { + echo "jq is not installed. Please install jq and try again." + exit 1 +} + +SCRIPT_DIR="$(readlink -f "$(dirname "$0")")" +MONOREPO_ROOT="$(readlink -f "$SCRIPT_DIR/../")" + +APP_VERSION="$(jq -r '.version' "$MONOREPO_ROOT/apps/web/package.json")" +GIT_SHA="$(git rev-parse HEAD)" + +echo "Building docker image for monorepo at $MONOREPO_ROOT" +echo "App version: $APP_VERSION" +echo "Git SHA: $GIT_SHA" + +docker build -f "$SCRIPT_DIR/Dockerfile" \ + --progress=plain \ + -t "documentso:latest" \ + -t "documenso:$GIT_SHA" \ + -t "documenso:$APP_VERSION" \ + "$MONOREPO_ROOT" diff --git a/docker/compose-entrypoint.sh b/docker/compose-entrypoint.sh new file mode 100755 index 000000000..36db6b41e --- /dev/null +++ b/docker/compose-entrypoint.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +SCRIPT_DIR="$(readlink -f "$(dirname "$0")")" +MONOREPO_ROOT="$(readlink -f "$SCRIPT_DIR/../")" + +cd "$MONOREPO_ROOT" + +npm ci + +npm run db-migrate:dev + +npm run dev diff --git a/docker/compose-without-app.yml b/docker/compose-without-app.yml new file mode 100644 index 000000000..dc9d91bda --- /dev/null +++ b/docker/compose-without-app.yml @@ -0,0 +1,16 @@ +services: + database: + image: postgres:15 + environment: + - POSTGRES_USER=documenso + - POSTGRES_PASSWORD=password + - POSTGRES_DB=documenso + ports: + - 5432:5432 + + inbucket: + image: inbucket/inbucket + ports: + - 9000:9000 + - 2500:2500 + - 1100:1100 diff --git a/docker/compose.yml b/docker/compose.yml new file mode 100644 index 000000000..a53b016d1 --- /dev/null +++ b/docker/compose.yml @@ -0,0 +1,40 @@ +services: + database: + image: postgres:15 + environment: + - POSTGRES_USER=documenso + - POSTGRES_PASSWORD=password + - POSTGRES_DB=documenso + ports: + - 5432:5432 + + inbucket: + image: inbucket/inbucket + ports: + - 9000:9000 + - 2500:2500 + - 1100:1100 + + documenso: + image: node:18 + working_dir: /app + command: ./docker/compose-entrypoint.sh + depends_on: + - database + - inbucket + environment: + - DATABASE_URL=postgres://documenso:password@database:5432/documenso + - NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000 + - NEXTAUTH_SECRET=my-super-secure-secret + - NEXTAUTH_URL=http://localhost:3000 + - SENDGRID_API_KEY= + - SMTP_MAIL_HOST=inbucket + - SMTP_MAIL_PORT=2500 + - SMTP_MAIL_USER=username + - SMTP_MAIL_PASSWORD=password + - MAIL_FROM=admin@example.com + - ALLOW_SIGNUP=true + ports: + - 3000:3000 + volumes: + - ../:/app diff --git a/package.json b/package.json index a993179f2..8d5ac7888 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,13 @@ "name": "documenso-monorepo", "version": "0.0.0", "scripts": { - "dev": "cd apps && cd web && next dev", + "dev": "npm run dev -w apps/web", "build": "npm i && cd apps && cd web && npm i && next build", "start": "cd apps && cd web && next start", "db-migrate:dev": "prisma migrate dev", "db-seed": "prisma db seed", - "db-studio": "prisma studio" + "db-studio": "prisma studio", + "dx": "./scripts/dx.sh" }, "workspaces": [ "apps/*", @@ -49,4 +50,4 @@ "prettier": "^2.8.7", "prettier-plugin-tailwindcss": "^0.2.5" } -} +} \ No newline at end of file diff --git a/scripts/dx.sh b/scripts/dx.sh new file mode 100755 index 000000000..ac71645fe --- /dev/null +++ b/scripts/dx.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +SCRIPT_DIR="$(readlink -f "$(dirname "$0")")" +MONOREPO_ROOT="$(readlink -f "$SCRIPT_DIR/../")" + +# Check if docker is installed +if ! command -v docker >/dev/null 2>&1; then + echo "Docker is not installed. Please install Docker and try again." + exit 1 +fi + +# Check if docker-compose is installed +if ! command -v docker-compose >/dev/null 2>&1; then + echo "Docker Compose is not installed. Please install Docker Compose and try again." + exit 1 +fi + +# Check if we have a .env file +if [ ! -f "$MONOREPO_ROOT/.env" ]; then + echo "No .env file found. Please create one and try again." + echo "See .env.example for an example." + exit 1 +fi + +# Change to the monorepo root directory +pushd "$MONOREPO_ROOT" >/dev/null + +# On failure popd back to the original directory +trap "popd >/dev/null" EXIT + +docker-compose -f "$MONOREPO_ROOT/docker/compose-without-app.yml" up -d + +# Install dependencies +npm ci + +# Migrate the database +npm run db-migrate:dev + +echo "All done! You can now start the app with: npm run dev" + +# Return to the original directory +popd >/dev/null