pnpm + Turborepo MonorepoをDocker化する最小構成
最近、pnpmとTurborepoで構築したMonorepoをDocker上で動かす機会があり、つまずきも多かったので備忘録として残しておこうと思います
Monorepoの構成例
今回のプロジェクトは以下のようなディレクトリ構造になっています。apps/service-a
のDockerfileがビルド対象です。
.
├── apps
│ ├── service-a # 実際に動かすアプリ
│ ├── service-b # 別のアプリ
│ └── service-c # さらに別のアプリ
├── packages
│ ├── utils # 共通ユーティリティ
│ ├── config # 共通のeslintやtsconfigなど
│ └── types # 型定義
├── turbo.json
├── pnpm-workspace.yaml
├── package.json
└── pnpm-lock.yaml
Dockerfile
FROM node:22-bookworm-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
# 依存関係のインストール
FROM base AS deps
WORKDIR /app
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY packages ./packages
COPY apps/service-a ./apps/service-a
RUN pnpm install --frozen-lockfile
# ビルド
FROM base AS build
WORKDIR /app
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY /app/node_modules ./node_modules
COPY /app/apps/service-a/node_modules ./apps/service-a/node_modules
COPY /app/packages ./packages
COPY apps/service-a ./apps/service-a
RUN pnpm run -r build
# 実行
FROM base AS runner
# curl(ヘルスチェック用)
RUN apt update && apt install -y curl \
&& apt clean && rm -rf /var/lib/apt/lists/*
COPY /app /app
EXPOSE 3000
WORKDIR /app/apps/service-a
CMD ["pnpm","start"]
詳しい解説
依存関係のインストールをしています
# 依存関係のインストール
FROM base AS deps
WORKDIR /app
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY packages ./packages
COPY apps/service-a ./apps/service-a
RUN pnpm install --frozen-lockfile
COPY packages ./packages
としているのは、packagesが増えた際に毎度Dockerfileを更新するのが面倒なためです。
RUN --mount=type=cache,id=pnpm,target=/pnpm/store
でキャッシュを効かせてビルドを高速化します。
つまづいた点
.tsbuildinfo
の存在
TypeScriptをincremental
やproject references
でビルドしている場合、.tsbuildinfo
ファイルが生成されます。
これはキャッシュ情報であり、基本的には削除不要ですが、Dockerビルドの際にdist
が存在しないのに「ビルド済み」となってしまい、distが存在しないのでpackagesがappsから参照できないということがありました。
.dockerignore
で.tsbuildinfo
を指定しておきましょう。
tsconfig.json
でpath
を指定すると、意図しないdistが生成されてしまう
モノレポ構成で tsconfig.json
の paths
を使ってパッケージを参照していたところ、アプリをビルドすると dist/apps/...
の中にパッケージのソースファイルが展開されてしまうという現象にハマりました。
そのせいで、
CMD ["pnpm","start"]
で指定しているdist/index.js
のパスがずれてしまい、アプリが起動できませんでした。
"paths": {
"@Application/types": [
"../../packages/types/src/index"
],
"@Application/types/*": [
"../../packages/types/src/*"
]
}
そこで、tsconfig.json
のreferences
を使用しました。
"references": [
{
"path": "../../packages/types"
}
]
採用情報
架電特化のAI電話SaaSを展開しているnocall.ai株式会社では、エンジニアを積極採用中です!
ジュニア層のエンジニアからリーダー職まで幅広く募集しています。
興味をもっていただいた方はカジュアル面談でぜひお話ししましょう!
Xもフォローしてください!
Discussion