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

prisma generate panics when building docker image on alpine base #466

Open
StoicDeveloper opened this issue Aug 16, 2024 · 3 comments
Open

Comments

@StoicDeveloper
Copy link

StoicDeveloper commented Aug 16, 2024

When attempting to generate prisma.rs while building an alpine-based image, the binary panics with an OS "No such file or directory" error, which occurs on the prisma_cli.rs cmd.output().unwrap() call, as detailed in the stack trace below.

The build works fine when using a debian base image, but I wanted to use alpine since the resulting image size is 10x larger with debian.

Here is the relevant dockerfile stage:

FROM rust:alpine AS builder-alpine
RUN rustup default nightly
RUN apk add --update musl-dev libressl-dev
WORKDIR /app
COPY ./src-server .
RUN RUST_BACKTRACE=1 cargo prisma generate
RUN cargo build --release

The build output indicating the failing line:

------                                         
Dockerfile:28                                  
--------------------                           
  26 |     WORKDIR /app
  27 |     COPY ./src-server .
  28 | >>> RUN RUST_BACKTRACE=1 cargo prisma generate                                          
  29 |     RUN cargo build --release 
  30 |     # RUN apk add bash curl
--------------------                           
ERROR: failed to solve: process "/bin/sh -c RUST_BACKTRACE=1 cargo prisma generate" did not complete successfully: exit code: 101

@StoicDeveloper
Copy link
Author

Build output including stack trace:

602.7     Finished `dev` profile [unoptimized + debuginfo] target(s) in 10m 01s                                                                                                               
603.4      Running `/target/debug/prisma generate`                                                                                                                                            
603.4 Downloading https://prisma-photongo.s3-eu-west-1.amazonaws.com/prisma-cli-4.8.0-linux-x64.gz to /root/.cache/prisma/binaries/cli/4.8.0/prisma-cli-linux-x64                             
736.9 Downloading https://binaries.prisma.sh/all_commits/d6e67a83f971b175a593ccc12e15c4a757f93ffe/linux-musl/query-engine.gz to /root/.cache/prisma/binaries/cli/4.8.0/d6e67a83f971b175a593ccc
12e15c4a757f93ffe/prisma-query-engine-linux-musl                                                                                                                                              
738.6 Downloading https://binaries.prisma.sh/all_commits/d6e67a83f971b175a593ccc12e15c4a757f93ffe/linux-musl/migration-engine.gz to /root/.cache/prisma/binaries/cli/4.8.0/d6e67a83f971b175a59
3ccc12e15c4a757f93ffe/prisma-migration-engine-linux-musl                                                                                                                                      
740.1 Downloading https://binaries.prisma.sh/all_commits/d6e67a83f971b175a593ccc12e15c4a757f93ffe/linux-musl/introspection-engine.gz to /root/.cache/prisma/binaries/cli/4.8.0/d6e67a83f971b17
5a593ccc12e15c4a757f93ffe/prisma-introspection-engine-linux-musl                                                                                                                              
741.9 Downloading https://binaries.prisma.sh/all_commits/d6e67a83f971b175a593ccc12e15c4a757f93ffe/linux-musl/prisma-fmt.gz to /root/.cache/prisma/binaries/cli/4.8.0/d6e67a83f971b175a593ccc12
e15c4a757f93ffe/prisma-prisma-fmt-linux-musl                                                                                                                                                  
742.5 thread 'main' panicked at /cargo/git/checkouts/prisma-client-rust-fa967aa5ad0ec391/3ac68d0/cli/src/prisma_cli.rs:40:18:                                                                 
742.5 called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }                                                                       
742.5 stack backtrace:                                                                                                                                                                        
743.0    0: rust_begin_unwind                                                                                                                                                                 
743.0              at /rustc/13a52890dde8cfeb95069d77c223ac37c0cf3a46/library/std/src/panicking.rs:662:5                                                                                      
743.0    1: core::panicking::panic_fmt                                                                                                                                                        
743.0              at /rustc/13a52890dde8cfeb95069d77c223ac37c0cf3a46/library/core/src/panicking.rs:74:14                                                                                     
743.0    2: core::result::unwrap_failed                                                                                                                                                       
743.0              at /rustc/13a52890dde8cfeb95069d77c223ac37c0cf3a46/library/core/src/result.rs:1679:5
743.0    3: core::result::Result<T,E>::unwrap
743.0              at /rustc/13a52890dde8cfeb95069d77c223ac37c0cf3a46/library/core/src/result.rs:1102:23
743.0    4: prisma_client_rust_cli::prisma_cli::main                                           
743.0              at /cargo/git/checkouts/prisma-client-rust-fa967aa5ad0ec391/3ac68d0/cli/src/prisma_cli.rs:40:5
743.0    5: prisma_client_rust_cli::run
743.0              at /cargo/git/checkouts/prisma-client-rust-fa967aa5ad0ec391/3ac68d0/cli/src/lib.rs:16:9
743.0    6: prisma::main
743.0              at ./src/bin/prisma.rs:2:5
743.0    7: core::ops::function::FnOnce::call_once                                             
743.0              at /rustc/13a52890dde8cfeb95069d77c223ac37c0cf3a46/library/core/src/ops/function.rs:250:5
743.0 note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.  

@delsehi
Copy link

delsehi commented Aug 23, 2024

I've also played around with alpine containerfiles.

Containerfile

ARG RUST_VERSION=1.80.1
ARG APP_NAME=my_app
FROM rust:${RUST_VERSION}-alpine AS build
ARG APP_NAME
WORKDIR /app
RUN apk update && \
    apk add openssl musl-dev openssl-dev pkgconf && \
    cargo install cargo-chef
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
RUN cargo prisma generate && cargo build --locked --release 

FROM alpine:latest AS final 

RUN apk update && apk upgrade openssl
COPY --from=build "/app/target/release/my_app" /usr/local/bin
EXPOSE 3000
ENTRYPOINT ["/usr/local/bin/my_app"]

Cargo.toml

[package]
name = "my_app"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1.0.86"
askama = { version = "0.12.1", features = ["with-axum"] }
askama_axum = "0.4.0"
axum = "0.7.5"
axum-extra = { version = "0.9.3", features = ["cookie-private"] }   
dotenvy = "0.15.7"
openidconnect = "3.5.0"
reqwest = { version = "0.12.5", features = ["json"] }
serde = { version = "1.0.206", features = ["derive"] }
serde_json = "1.0.124"
tokio = { version = "1.39.2", features = ["full"] }
tower = "0.4.13"
tower-http = { version = "0.5.2", features = ["fs", "trace"] }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust", tag = "0.6.11", default-features = false, features = [
    "mssql",
] }

[workspace]

members = ["prisma-cli"]

resolver = "2"

My container won't run but it builds, so hopefully it helps you past that at least? 😄

@Seiyial
Copy link

Seiyial commented Oct 24, 2024

@StoicDeveloper @delsehi

Hey y'all, I just spent the whole night getting my discord bot deployed on Alpine Linux on Railway and after a lot of pain, failures, 15 minute docker builds and a lot of googling and debugging I DID IT!

Summary of the gotchas I found

  • I did some debug digging into find the file path that the prisma rust cli was trying to call, to the extent of adding print statements to see what the actual command was. Turns out, prisma-client-rust-cli actually installed it at the right place, and tried to execute the right file path that was downloaded. The problem was something that blew my mind: in Alpine Linux, it is possible to have a file that when you execute says "file not found". Here's the explanation. I followed their solution to apk add libc6-compat. Doing so brought me forward from a file not found error to a "We're running the file, yay! But you don't have libssl1.1 and libcrypto1.1 installed. Failed" error. I'll cover them next.
  • prisma-client-rust uses the OG Prisma (JS)'s version 4.8.0's engines. This version claims to support not just OpenSSL 1.1, but is the first ever Prisma version to support OpenSSL 3.0.x on the (I'm guessing) latest Alpine Linux 3.17 at that time. The engines we get are downloaded from the same source as the JS version, so I believe this applies to us. HOWEVER, Alpine 3.18 ships with OpenSSL 3.1 by default. Alpine 3.20 ships with OpenSSL 3.3, and if you install postgresql-dev as recommended by this library it becomes OpenSSL 3.4. I'm guessing that it is for this reason we don't automatically get to use the Prisma engine for linux-musl-openssl3.0.x. We get the linux-musl Prisma engine (you can see it when you do cargo run --bin prisma; the URL from which it is downloading. If it is linux-musl it is the OpenSSL 1.1 variant; if it is linux-musl-openssl3.0.x it is the OpenSSL3.0.x variant. Prisma's team gives the binary download link breakdown here, and the list of variants here. So unless you happen to be using an x86_64 (so no ARM) Alpine Linux in 3.17 (I believe) (and now it's 3.20), you will not get the OpenSSL 3.0.x variant, and will need OpenSSL 1.1 to be available and probably linked. If you don't, your prisma generate will probably fail. It would give you a -lssl, -lcrypto file not found error. And if you made it, the actual runtime would fail saying there are missing symbols.
  • You need perl to compile OpenSSL. If you don't have perl installed and rust is somehow trying to compile openssl for you, it will fail. Interestingly, when it failed for me for this reason, perl was not mentioned once, but instead a -lssl, -lcrypto error was given. But when I did it again with an apk add perl, I managed to proceed.
  • I used Alpine 3.18 with openssl1.1-compat because the latest Alpine 3.20 (at time of writing) does not offer openssl1.1-compat; only edge branch and <=3.18 does.
  • OpenSSL 1.1 is EOL'd last year; and I don't recommend doing this for any project where there is sensitive user data that people have good reason to attack. I suggest trying 3.17, getting the needed postgresql libraries (if using postgresql) without using a package that upgrades OpenSSL beyond 3.0.x. I'll update here if I have time to try it, and get it to work.
  • You may also get the -lssl and -lcrypto errors by using the rust alpine default docker image and doing everything normally. Something to do with dynamic vs static linking that I don't feel qualified enough to explain myself, and I'm not completely sure if this is related. But it surely convinced me to not use the rust alpine docker image and use my own instead so I know what it's made of. here. And/or apk add openssl-libs-static.
  • And even with everything sorted out, my prisma generate succeeded as a build step, but did not generate a file. So I used prisma generate on my device, and changed the absolute path at the top of the file to a relative path to schema.prisma from the autogenerate file's directory. (So ../prisma/schema.prisma).
  • I also connected to the database to do migrations without using the Alpine Linux runtime. I was too tired at this point to try to make it part of the build. Luckily my app doesn't do frequent deploys.
  • Now my database calls are working, via prisma's query engine, running libssl1.1, prisma 4.8.0. God.

What works for me

# FROM rust:1.82.0-alpine as builder
FROM alpine:3.18 AS planner

# musl-dev is C lib
RUN apk add --no-cache musl-dev postgresql-dev gcc curl openssl-libs-static perl openssl1.1-compat libc6-compat
RUN curl -tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
# prefer -proto 'https'
ENV PATH="$HOME/.cargo/bin:${PATH}"

WORKDIR /app
COPY . .
RUN cargo build --release
RUN mkdir -p bin && cp target/release/myappname bin

# # ensure we have DATABASE_URL
ARG DATABASE_URL
# other env vars

CMD ./bin/myappname

From writing this post I can see many ways prisma-client-rust can improve, but am not confident in having the time and energy to absorb this codebase and see where to start. It is an amazing thing that we get to use something of Prisma's production calibre in the hinterlands of Rust, but at the same time our guy is busy and just one guy, and so it is a little sad that (imo) the best ORM doesn't get to meet Rust in a way that OG Prisma meets TypeScript.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants