DistrolessコンテナでPrismaを動かす

DistrolessコンテナでPrismaを動かす

2023-01-144 min read

目次

  1. 概要
  2. distrolessprismaを構築するためのポイント
  3. 動作不良の原因
  4. 対策
  5. dockerfile
  6. 所感
  7. 参考にしたサイト

概要

Prismaを利用するアプリケーションをDistrolessコンテナで動作させようとした際に、 依存関係の調整を行うことで動作させました。 その際のノートです。

動作させるための要点は

  • OpenSSLの導入
  • シェルコマンド依存箇所の調整
  • Primsaエンジンの調整

となります。

そして、結局のところPrismaをdistrolessで利用すべきではないと思ったので、 それについても話しています。

またPrismaアプリケーションの構築の話は割愛しています。

Distrolessについて

GoogleContainerTools/distroless: 🥑 Language focused docker images, minus the operating system.

必要最低限のアプリケーションとそのランタイム依存関係のみが含まれるコンテナイメージです。

Distroless+Prismaを構築するためのポイント

冒頭にも書いたとおり、Distrolessコンテナ+Prismaを動作させる際にポイントとなったのは

  • OpenSSLの調整
  • シェルコマンド依存箇所の調整
  • Primsaエンジンの調整

でした。

ここの依存関係の調整がうまくいっていない場合、次のようなエラーが発生します。

/snapshot/app/node_modules/@prisma/client/runtime/index.js:27675
      throw new PrismaClientInitializationError(
            ^
Error: Unknown PRISMA_QUERY_ENGINE_LIBRARY linux-arm64-openssl-undefined. Possible binaryTargets: darwin, darwin-arm64, debian-openssl-1.0.x, debian-openssl-1.1.x, debian-openssl-3.0.x, rhel-openssl-1.0.x, rhel-openssl-1.1.x, rhel-openssl-3.0.x, linux-arm64-openssl-1.1.x, linux-arm64-openssl-1.0.x, linux-arm64-openssl-3.0.x, linux-arm-openssl-1.1.x, linux-arm-openssl-1.0.x, linux-arm-openssl-3.0.x, linux-musl, linux-musl-openssl-3.0.x, linux-nixos, windows, freebsd11, freebsd12, freebsd13, openbsd, netbsd, arm, native or a path to the query engine library.
You may have to run prisma generate for your changes to take effect.

動作不良の原因

Prismaのソースをデバッグすると、 packages/engine-core/src/library/LibraryEngine.ts で例外が投げられていることがわかりました。

prisma/LibraryEngine.ts at main · prisma/prisma

さらに読んでいくと環境情報のチェックをおこなっていると思われる packages/get-platform/src/getPlatform.ts で、OpenSSLに関する情報の取得に失敗していることがわかりました。

prisma/getPlatform.ts at main · prisma/prisma

この部分を整理すると要因は次の関係と言えそうです。

OpenSSLの存在チェックに失敗
  ↓
OpenSSLの存在チェックを行うためのOSのコマンドの実行に失敗
  ↓
- nodeのexecを実行するためのシェル環境が存在しない
- zlib(libz.so)が存在しない
- 関連コマンドが存在しない
- OpenSSLが存在しない

またこれ以外にprismaエンジンの読み込みに失敗もしていました。

対策

上記のような問題がある中でどのような対応を行い動作させたかについて書きます。

実装の詳細について下記のDockerfileに記載しています。

OpenSSLの存在チェック

上記で触れたOpenSSLの存在チェックは次の条件で行われていました。

  1. /usr/lib/{aarch64 or x86_64}-linux-gnu or /lib/${aarch64 or x86_64}-linux-gnulibssl.soが存在するか
  • debian系以外のディストロでは/liblib64がチェックされます
  1. ldconfig -p の結果にsslが存在するか
  2. openssl version -vの結果が返ってくるか

なので、これらのチェックの機能が動くように調整します。

zlib(libz.so)が存在しない

OpenSSLのみを何らかの形でインストールしたとしても依存関係でzlibが必要となります。 この場合、opensslが次の様なエラーを吐きます。

openssl: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory

なので、zlibもインストールを行います。

最低限のコマンド実行環境の用意

Distrolessはシェル(/bin/sh)が存在しません。 なのでなんとかしてシェルを動かす必要があります。

busyboxから/bin/sh を移すことで対応してみました。

Prismaエンジンの読み込みに失敗する問題の対策

Prismaエンジンの読み込みに失敗すると次の様なエラーが出ます。

/app/index.js:42581
      throw new PrismaClientInitializationError(errorText, this.config.clientVersion);
            ^
Error: Query engine library for current platform "linux-arm64-openssl-3.0.x" could not be found.
You incorrectly pinned it to linux-arm64-openssl-3.0.x

This probably happens, because you built Prisma Client on a different platform.
(Prisma Client looked in "/app/libquery_engine-linux-arm64-openssl-3.0.x.so.node")

Searched Locations:

  /.prisma/client
  /app/node_modules/@prisma/client
  /
  /app
  /app
  /tmp/prisma-engines
  /app

この問題についてはソースをバンドルしてコンテナをビルドしたことによる影響だったので 環境の問題とは異なりますが、Prismaエンジンが正しく読み込めるよう解決させる必要がありました。

Dockerfile

gcr.io/distroless/nodejs18-debian11

gcr.io/distroless/nodejs18-debian11 の場合は次の内容のDockerfileを定義吸えうことで動作しました。

FROM node:18 as builder

# zlibの構築に必要なものを取得
RUN apt-get -y update && apt-get -y install -y wget perl gcc make

WORKDIR /tmp
# zlibを/optに入れて他の依存関係を壊さないようにインストールし、
# 最終的にアプリケーションコンテナにコピーする
RUN wget https://www.zlib.net/zlib-1.2.13.tar.gz &&\
  tar -xvf zlib-1.2.13.tar.gz &&\
  cd zlib-1.2.13 &&\
  ./configure  --prefix="/opt/local" &&\
  make &&\
  make install

# OpenSSL 3.0.xを利用したい場合
# RUN wget https://www.openssl.org/source/openssl-3.0.7.tar.gz &&\
#   tar -xvf openssl-3.0.7.tar.gz &&\
#   cd openssl-3.0.7 &&\
#   ./Configure \
#   shared zlib \
#   --with-zlib-include="/opt/local/include/" \
#   --with-zlib-lib="/opt/local/lib/" \
#   --prefix="/opt/local" &&\
#   make && make install_sw

ENV LD_LIBRARY_PATH /opt/local/lib:/$LD_LIBRARY_PATH
ENV PATH /opt/local/bin:/$PATH

WORKDIR /app
RUN mkdir -p /app
COPY . /app
RUN npm install
# バンドルにnccを利用しました。
# nccでコンパイルした場合、prismaエンジンがprisma実行時に参照できない場所に配置されるので
# 調整しています。
RUN npx ncc build src/main.ts -o dist/ && cp dist/client/libquery_engine-* dist

# busyboxのイメージから /bin/sh をコピーするために定義します。
FROM busybox:1.35.0-uclibc as busybox

FROM gcr.io/distroless/nodejs18-debian11 as app
COPY --from=builder /opt/local/lib /opt/local/lib
COPY --from=busybox /bin/sh /bin/sh
COPY --from=builder --chown=nonroot:nonroot /app/dist /app
ENV NODE_ENV production
ENV LD_LIBRARY_PATH /opt/local/lib:/lib:/$LD_LIBRARY_PATH
# /optの下に入れたopensslを利用する場合は有効にする。
# ENV PATH /opt/local/bin:/$PATH
# 任意のDBホスト
ENV DATABASE_URL "mysql://docker:docker@host.docker.internal:3306/app"
WORKDIR /app
USER nonroot
EXPOSE 3000
CMD [ "/app/index.js" ]

所感

強引な方法でDistrolessでPrismaを動かすことはできましたが、 シェル環境が必要だったことを考えるとdebianなどの通常のディレストリビューションのイメージの 方が良いのではと思いました。

参考にしたサイト

Tags
javascript(110)
node.js(54)
linux(54)
amazon%20aws(47)
typescript(45)
%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0(36)
%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86(30)
html5(29)
php(24)
centos(24)
python(22)
%E7%AB%B6%E6%8A%80%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0(21)
mac(21)
mysql(20)
canvas(19)
opencv(17)
%E9%9B%91%E8%AB%87(16)
docker(16)
wordpress(15)
atcoder(14)
apache(12)
%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92(12)
%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9(12)
amazon%20s3(12)
red%20hat(12)
prisma(12)
ubuntu(11)
github(10)
git(10)
vue.js(10)
%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86100%E6%9C%AC%E3%83%8E%E3%83%83%E3%82%AF(10)
mariadb(10)
react(9)
aws%20cdk(9)
css3(8)
%E5%8F%AF%E8%A6%96%E5%8C%96(8)
%E5%B0%8F%E3%83%8D%E3%82%BF(8)
nestjs(8)
amazon%20lightsail(7)
next.js(7)
%E3%83%96%E3%83%AD%E3%82%B0(6)
cms(6)
oracle(6)
perl(6)
gitlab(6)
iam(5)
amazon%20ec2(5)
%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93(5)
aws%20amplify(5)
curl(4)
Author
githubzennqiita
ただの備忘録です。

※外部送信に関する公表事項