Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Serverless: OS Support Initiative): Document how to use Prisma with Docker / Linux Distros #4365

Open
1 task
Tracked by #4721
jkomyno opened this issue Jan 5, 2023 · 3 comments
Open
1 task
Tracked by #4721
Assignees
Labels
docs Documentation creation, updates or corrections serverless-initiative See #orm-discovery-deployment-and-docs topic: serverless

Comments

@jkomyno
Copy link
Contributor

jkomyno commented Jan 5, 2023

Setting up Prisma on Docker environments is non-trivial, as plenty of comments in our Github issues demonstrate.
We should prepare a tutorial page that describes step-by-step how to use Prisma in the most popular Docker images, both for deploying serverless services (e.g., via AWS Fargate + AWS ECS) and for local development.
We should also take system architecture differences between the users host machine and their runtime machine into account (e.g., macOS users with Silicon CPUs won't be able to use alpine-based images locally unless they use Docker Buildx with --platform="linux/amd64", as Prisma doesn't work on Alpine on arm64: prisma/prisma#8478)

We should target the following system scenarios, inspired from our ecosystem-tests:

  • node:lts-alpine3.17 (and variants, like node:lts-alpine, node:alpine) on amd64 and arm64
  • node:16-slim (and variants, like node:lts-buster-slim) on amd64 and on arm64
  • gcr.io/distroless/nodejs18-debian11 on amd64

Opinable, these were mainly relevant when prisma didn't support openssl 3 or for users with weird linuxbrew/snap setups, which are arguably not generally used for serverless and local development on Docker:

  • ubuntu:20.04 on amd64
  • ubuntu:22.04 on amd64

We should show our users how to:

  • install Prisma on Docker (with the above scenarios, installing missing system dependencies when needed)
  • connect to a database (e.g., Postgres locally exposed via docker-compose.yaml, whose URL one can configure when building the Docker image)
  • running prisma db push
  • generate types
  • use the Prisma Client

For constrained, barebone environments (such as gcr.io/distroless images and actual serverless services) we should tell users to write multi-stage Dockerfiles and only deploy the Prisma Client, delegating commands like prisma db push and prisma generate to a previous docker stage.

On Linux Alpine we should tell users not to install libc.

Motivating issues

TODOs

  • Check whether installing libc6-compat on Alpine for amd64 breaks anything with Prisma
@jkomyno jkomyno added docs Documentation creation, updates or corrections topic: serverless serverless-initiative See #orm-discovery-deployment-and-docs labels Jan 5, 2023
@jkomyno
Copy link
Contributor Author

jkomyno commented Jan 5, 2023

This follows up on #4303 .

@jkomyno jkomyno changed the title (Serverless: OS Support Initiative): Document how to use Prisma with Docker (Serverless: OS Support Initiative): Document how to use Prisma with Docker / Linux Distros Jan 24, 2023
@jkomyno
Copy link
Contributor Author

jkomyno commented Jan 25, 2023

Follow-up TODOs

@jkomyno
Copy link
Contributor Author

jkomyno commented Jan 30, 2023

Working on this draft:


How to run Prisma on Docker

Prisma supports the most of the popular Docker images for Node.js out of the box.
However, due to the system dependencies the Prisma engines rely on and the complexities of providing compiled binaries for all operating systems and CPU architectures, some adjustments may be needed.

In this tutorial, we'll walk you through the process of setting up a Docker container for a Node.js application that uses Prisma. Given a simple Prisma schema, an empty Postgres database, and a basic Express.js server running on port 3000, we'll create a Docker image that initialises Prisma, runs the server and connects to the database.

Preliminaries

Create a new prisma-docker-tutorial directory, open it, and paste the following files in there:

// ./prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgres"
  url      = env("DATABASE_URL")
}

model Author {
  id   Int      @id
  post Post[]
}

model Post {
  id     Int    @id
  user   Author @relation(fields: [userId], references: [id])
  userId Int
}
// ./server.js
const express = require('express')
const app = express()
const port = 3000

const { PrismaClient } = require('@prisma/client')

const client = new PrismaClient()

app.get('/', async (req, res) => {
  const data = await client.user.findMany()
  res.send(JSON.stringify(data))
})

app.listen(port, () => {
  console.log(`App listening at http://localhost:${port}`)
})
// ./package.json
{
  "name": "@prisma/docker-tutorial",
  "license": "MIT",
  "devDependencies": {
    "prisma": "4.10.0"
  },
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "@prisma/client": "4.10.0",
    "express": "4.18.2"
  }
}
./docker-compose.yml
version: '3.7'

services:
  postgres:
    image: postgres:15
    hostname: postgres_db
    restart: always
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=prisma
      - POSTGRES_PASSWORD=prisma
    ports:
      - '5432:5432'
    networks:
      - prisma-network

  prismacmd:
    image: prisma-docker-tutorial
    stdin_open: true
    environment:
      - DATABASE_URL=postgresql://prisma:prisma@postgres_db:5432/postgres
    depends_on:
      - postgres
    networks:
      - prisma-network

networks:
  prisma-network:
    name: prisma-network

This tutorial has been tested on Docker version 20.10.16.


We define the ./Dockerfile as follows:

Linux Alpine (node:alpine)

This is the default Docker image for Node.js. It is based on Alpine Linux, which is a lightweight Linux distribution that uses the musl C standard library.
Prisma supports Alpine on amd64 out of the box, and supports it on arm64 since prisma@4.10.0.

Related Docker images:

  • node:lts-alpine
  • node:16-alpine
  • node:14-alpine
# syntax=docker/dockerfile:1
FROM node:lts-alpine3.17

WORKDIR /usr/src/app
COPY --from=app . ./

RUN npm i \
  && npx prisma generate

EXPOSE 3000
ENTRYPOINT ["node", "server.js"]

Note: when running on Linux Alpine, Prisma downloads engines that are compiled for the musl C standard library. Please don't install glibc on Alpine (e.g., via the libc6-compat package), as that would prevent Prisma from running successfully.


Linux Debian (node:slim)

This image is based on Linux Debian, and uses the glibc C standard library.
It is mostly supported out of the box on amd64 and arm64, but as some older versions of this image come without libssl installed, it is sometimes necessary to install it manually.

Related Docker images:

  • node:lts-slim
  • node:bullseye-slim
  • node:buster-slim
  • node:stretch-slim
# syntax=docker/dockerfile:1
FROM node:slim

# Note: uncomment the following block if you're using an image based on Debian Buster, which doesn't come with libssl pre-installed
RUN apt-get update -y \
  && apt-get install -y openssl

WORKDIR /usr/src/app
COPY --from=app . ./

RUN npm install \
  && npx prisma generate

EXPOSE 3000
ENTRYPOINT ["node", "server.js"]

Distroless (gcr.io/distroless/nodejs18-debian11)

Distroless images are a set of minimal images containing only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution, which is great for the security of the system.

Although this image is originally based on Linux Debian Bullseye, some manual care is required before it can be used with Prisma. In particular, commands like npm install and prisma generate must be run in a separate build stage, as the distroless image doesn't come with npm or a shell pre-installed. Moreover, the zlib system dependency is missing, and must be copied from a compatible Debian image manually.

On Distroless, only the amd64 architecture is supported.

# syntax=docker/dockerfile:1

# Build stage on Debian 11
FROM node:18-bullseye-slim as deps

WORKDIR /usr/src/app
COPY --from=app . ./

# Uncomment the following block if you're using an image based on Debian Buster, which doesn't come with libssl pre-installed
RUN apt-get update -y \
  && apt-get install -y openssl

WORKDIR /usr/src/app
COPY . ./

RUN npm i \
  && npx prisma generate

# Runtime stage on Distroless
FROM gcr.io/distroless/nodejs18-debian11 as runtime

WORKDIR /usr/src/app
COPY --from=deps /usr/src/app/ ./

# Copy zlib from Debian, which is needed by Prisma
COPY --from=deps /lib/x86_64-linux-gnu/libz.so.1 /lib/x86_64-linux-gnu/libz.so.1

# the distroless' image entrypoint is /nodejs/bin/node
CMD ["server.js"]
EXPOSE 3000

jyecusch added a commit to nitrictech/cli that referenced this issue May 22, 2023
We may remove these fixes in future and allow developers to resolve
these issues themselves through custom docker files. For now though,
they have no impact on projects that aren't running prisma.

Related issues can be found here:
- prisma/docs#4365
- prisma/prisma#16901 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation creation, updates or corrections serverless-initiative See #orm-discovery-deployment-and-docs topic: serverless
Projects
None yet
Development

No branches or pull requests

1 participant