Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ jobs:
- debian-latest-amd64-openssl-1.1.x
- debian-latest-arm64-openssl-1.1.x
- debian-stretch-amd64-openssl-1.1.x
- distroless-bullseye-amd64-openssl-1.1.x
- opensuse-tumbleweed-amd64-openssl-3.0.x
- redhat-ubi9-amd64-openssl-3.0.x
- ubuntu-20.04-amd64-openssl-1.1.x
Expand Down Expand Up @@ -274,6 +275,7 @@ jobs:
feature:
- debian-buster-amd64-openssl-1.1.x
- debian-latest-arm-openssl-1.1.x
- distroless-bullseye-amd64-openssl-1.1.x-without-zlib
clientEngine: [library, binary]
os: [ubuntu-20.04]
runs-on: ${{ matrix.os }}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# syntax=docker/dockerfile:1

# expected target architecture, retrieved by `uname -m`
ARG EXPECTED_UNAME_ARCH="x86_64"

# We have to use a Docker pipeline to install dependencies on Debian Bullseye
# and then copy them to a distroless image.

# Install dependencies on Debian Bullseye
FROM node:18-bullseye-slim as deps

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

# Update system dependencies
RUN apt-get update -y

ARG EXPECTED_UNAME_ARCH
ENV EXPECTED_UNAME_ARCH=$EXPECTED_UNAME_ARCH
RUN ./uname.sh

# Only OpenSSL 1.1 is expected to be on this system
RUN ldconfig -p | grep ssl | sed "s/.*=>\s*//"
RUN if [ ! -e /usr/lib/${EXPECTED_UNAME_ARCH}-linux-gnu/libssl.so.1.1* ]; then echo "OpenSSL 1.1 not found in /usr/lib/${EXPECTED_UNAME_ARCH}-linux-gnu/libssl.so.1.1*"; exit 1; fi
RUN if [ -e /usr/lib/${EXPECTED_UNAME_ARCH}-linux-gnu/libssl.so.3* ]; then echo "OpenSSL 3 must not be installed (found in /usr/lib/${EXPECTED_UNAME_ARCH}-linux-gnu/libssl.so.3*)"; exit 1; fi

# expected target platform for Prisma, retrieved by `prisma -v`
ARG EXPECTED_PRISMA_TARGET_PLATFORM="debian-openssl-1.1.x"
ARG PRISMA_CLIENT_ENGINE_TYPE
ARG PRISMA_CLI_QUERY_ENGINE_TYPE
ARG CI
ARG DEBUG
ARG PRISMA_TELEMETRY_INFORMATION

ENV PRISMA_CLIENT_ENGINE_TYPE=$PRISMA_CLIENT_ENGINE_TYPE
ENV PRISMA_CLI_QUERY_ENGINE_TYPE=$PRISMA_CLI_QUERY_ENGINE_TYPE
ENV CI=$CI
ENV DEBUG=$DEBUG
ENV PRISMA_TELEMETRY_INFORMATION=$PRISMA_TELEMETRY_INFORMATION
ENV EXPECTED_PRISMA_TARGET_PLATFORM=$EXPECTED_PRISMA_TARGET_PLATFORM

RUN yarn install
RUN ./version.sh
RUN npx prisma generate

# Move dependencies to the distroless image, which contains Node.js, a version of glibc compatible
# with the Node.js version installed and libssl, but no zlib.
FROM gcr.io/distroless/nodejs18-debian11:debug as runtime

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

# This fails with:
# PrismaClientInitializationError: Unable to load Node-API Library from /usr/src/app/node_modules/.prisma/client/libquery_engine-debian-openssl-1.1.x.so.node, Library may be corrupt: libz.so.1: cannot open shared object file: No such file or directory
# at DefaultLibraryLoader.loadLibrary (/usr/src/app/node_modules/@prisma/client/runtime/index.js:27280:17)
# at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
# at async LibraryEngine.loadEngine (/usr/src/app/node_modules/@prisma/client/runtime/index.js:27586:24)
# at async LibraryEngine.instantiateLibrary (/usr/src/app/node_modules/@prisma/client/runtime/index.js:27541:5) {
# clientVersion: '4.10.0-dev.42',
# errorCode: undefined
# }
CMD ["server.js"]
EXPOSE 3000
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# OS support: fail-distroless-bullseye-amd64-openssl-1.1.x-without-zlib

- Base Docker image: `gcr.io/distroless/nodejs18-debian11`
- OS: Linux Debian Bullseye, Distroless
- Arch: amd64 (x86_64)
- OpenSSL location: `/usr/lib/x86_64-linux-gnu/libssl.so.1.1`
- Binary target: `debian-openssl-1.1.x`

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.

Distroless images do not have the `libz.so.1` library by default, which is required by Prisma.
This means the following error is raised at startup:

```sh
PrismaClientInitializationError: Unable to load Node-API Library from /usr/src/app/node_modules/.prisma/client/libquery_engine-debian-openssl-1.1.x.so.node, Library may be corrupt: libz.so.1: cannot open shared object file: No such file or directory
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@prisma/fail-distroless-bullseye-amd64-openssl-1.1.x",
"license": "MIT",
"devDependencies": {
"@types/node": "14.18.36",
"prisma": "4.10.0-dev.42",
"ts-node": "10.9.1",
"typescript": "4.9.3"
},
"scripts": {
"start": "node server.js"
},
"dependencies": {
"@prisma/client": "4.10.0-dev.42",
"express": "4.18.2"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
generator client {
provider = "prisma-client-js"
}

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

model User {
id String @id @default(cuid())
email String @unique
name String?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/sh

set -eux
export DEBUG="*"

DOCKER_PLATFORM_ARCH="linux/amd64"
PRISMA_DOCKER_IMAGE_NAME="prisma-distroless-bullseye-amd64-openssl-1.1.x"

docker buildx build --load \
--platform="${DOCKER_PLATFORM_ARCH}" \
--build-context app=. \
--build-context utils=../../docker/_utils \
--build-arg DEBUG=${DEBUG} \
--build-arg PRISMA_TELEMETRY_INFORMATION="${PRISMA_TELEMETRY_INFORMATION}" \
--build-arg PRISMA_CLIENT_ENGINE_TYPE=${PRISMA_CLIENT_ENGINE_TYPE} \
--build-arg PRISMA_CLI_QUERY_ENGINE_TYPE=${PRISMA_CLIENT_ENGINE_TYPE} \
--build-arg CI=${CI} \
. -t "${PRISMA_DOCKER_IMAGE_NAME}" \
--progress plain

docker run -p 3000:3000 \
--platform="${DOCKER_PLATFORM_ARCH}" \
-e DEBUG=${DEBUG} \
-e DATABASE_URL=${DATABASE_URL} \
-e CI=${CI} \
-e PRISMA_CLIENT_ENGINE_TYPE=${PRISMA_CLIENT_ENGINE_TYPE} \
-e PRISMA_CLI_QUERY_ENGINE_TYPE=${PRISMA_CLIENT_ENGINE_TYPE} \
-e PRISMA_TELEMETRY_INFORMATION="${PRISMA_TELEMETRY_INFORMATION}" \
"${PRISMA_DOCKER_IMAGE_NAME}" &

sleep 15

yarn install
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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}`)
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh

set -eu

expected="[]"
actual=$(curl localhost:3000)

if [ "$expected" != "$actual" ]; then
echo "expected '$expected', got '$actual'"
docker stop $(docker ps -a -q)
exit 1
fi

echo "result: $actual"
docker stop $(docker ps -a -q)
Loading