Here’s a hasty attempt to create unified image. What I did is here is to merge web_serve
and api_serve
in a single target and comment out console
(so that last target is the one we want to actually serve, we don’t need it without docker-compose anyways).
Full file:
# base
# ----
FROM node:20-bookworm-slim as base
RUN corepack enable
# We tried to make the Dockerfile as lean as possible. In some cases, that means we excluded a dependency your project needs.
# By far the most common is Python. If you're running into build errors because `python3` isn't available,
# add `python3 make gcc \` before the `openssl \` line below and in other stages as necessary:
RUN apt-get update && apt-get install -y \
openssl \
&& rm -rf /var/lib/apt/lists/*
USER node
WORKDIR /home/node/app
COPY --chown=node:node .yarnrc.yml .
COPY --chown=node:node package.json .
COPY --chown=node:node api/package.json api/
COPY --chown=node:node web/package.json web/
COPY --chown=node:node yarn.lock .
RUN mkdir -p /home/node/.yarn/berry/index
RUN mkdir -p /home/node/.cache
RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
--mount=type=cache,target=/home/node/.cache,uid=1000 \
CI=1 yarn install
COPY --chown=node:node redwood.toml .
COPY --chown=node:node graphql.config.js .
COPY --chown=node:node .env.defaults .env.defaults
# api build
# ---------
FROM base as api_build
# If your api side build relies on build-time environment variables,
# specify them here as ARGs. (But don't put secrets in your Dockerfile!)
#
# ARG MY_BUILD_TIME_ENV_VAR
COPY --chown=node:node api api
RUN yarn rw build api
# web prerender build
# -------------------
FROM api_build as web_build_with_prerender
ARG CLERK_PUBLISHABLE_KEY
COPY --chown=node:node web web
RUN yarn rw build web
# web build
# ---------
FROM base as web_build
ARG CLERK_PUBLISHABLE_KEY
COPY --chown=node:node web web
RUN yarn rw build web --no-prerender
# api serve
# ---------
FROM node:20-bookworm-slim as serve
RUN corepack enable
RUN apt-get update && apt-get install -y \
openssl \
&& rm -rf /var/lib/apt/lists/*
USER node
WORKDIR /home/node/app
COPY --chown=node:node .yarnrc.yml .
COPY --chown=node:node package.json .
COPY --chown=node:node api/package.json api/
COPY --chown=node:node web/package.json web/
COPY --chown=node:node yarn.lock .
RUN mkdir -p /home/node/.yarn/berry/index
RUN mkdir -p /home/node/.cache
RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
--mount=type=cache,target=/home/node/.cache,uid=1000 \
CI=1 yarn workspaces focus --all --production
COPY --chown=node:node redwood.toml .
COPY --chown=node:node graphql.config.js .
COPY --chown=node:node .env.defaults .env.defaults
COPY --chown=node:node --from=api_build /home/node/app/api/dist /home/node/app/api/dist
COPY --chown=node:node --from=api_build /home/node/app/api/db /home/node/app/api/db
COPY --chown=node:node --from=api_build /home/node/app/node_modules/.prisma /home/node/app/node_modules/.prisma
COPY --chown=node:node --from=web_build /home/node/app/web/dist /home/node/app/web/dist
ENV NODE_ENV=production \
API_PROXY_TARGET=http://localhost:$API_PORT
# default api serve command
# ---------
# If you are using a custom server file, you must use the following
# command to launch your server instead of the default api-server below.
# This is important if you intend to configure GraphQL to use Realtime.
#
# CMD [ "./api/dist/server.js" ]
CMD [ "sh", "-c", "node_modules/.bin/rw-server api & node_modules/.bin/rw-web-server --api-proxy-target $API_PROXY_TARGET" ]
# # console
# # -------
# FROM base as console
# # To add more packages:
# #
# # ```
# # USER root
# #
# # RUN apt-get update && apt-get install -y \
# # curl
# #
# # USER node
# # ```
# COPY --chown=node:node api api
# COPY --chown=node:node web web
# COPY --chown=node:node scripts scripts
Diff:
diff --git a/Dockerfile b/Dockerfile
index c051185..3c1ccec 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -63,7 +63,7 @@ RUN yarn rw build web --no-prerender
# api serve
# ---------
-FROM node:20-bookworm-slim as api_serve
+ FROM node:20-bookworm-slim as serve
RUN corepack enable
@@ -77,6 +77,7 @@ WORKDIR /home/node/app
COPY --chown=node:node .yarnrc.yml .
COPY --chown=node:node package.json .
COPY --chown=node:node api/package.json api/
+ COPY --chown=node:node web/package.json web/
COPY --chown=node:node yarn.lock .
RUN mkdir -p /home/node/.yarn/berry/index
@@ -84,7 +85,7 @@ RUN mkdir -p /home/node/.cache
RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
--mount=type=cache,target=/home/node/.cache,uid=1000 \
- CI=1 yarn workspaces focus api --production
+ CI=1 yarn workspaces focus --all --production
COPY --chown=node:node redwood.toml .
COPY --chown=node:node graphql.config.js .
@@ -94,7 +95,10 @@ COPY --chown=node:node --from=api_build /home/node/app/api/dist /home/node/app/a
COPY --chown=node:node --from=api_build /home/node/app/api/db /home/node/app/api/db
COPY --chown=node:node --from=api_build /home/node/app/node_modules/.prisma /home/node/app/node_modules/.prisma
-ENV NODE_ENV=production
+ COPY --chown=node:node --from=web_build /home/node/app/web/dist /home/node/app/web/dist
+
+ ENV NODE_ENV=production \
+ API_PROXY_TARGET=http://localhost:$API_PORT
# default api serve command
# ---------
@@ -103,56 +107,23 @@ ENV NODE_ENV=production
# This is important if you intend to configure GraphQL to use Realtime.
#
# CMD [ "./api/dist/server.js" ]
-CMD [ "node_modules/.bin/rw-server", "api" ]
-
-# web serve
-# ---------
-FROM node:20-bookworm-slim as web_serve
-
-RUN corepack enable
-
-USER node
-WORKDIR /home/node/app
-
-COPY --chown=node:node .yarnrc.yml .
-COPY --chown=node:node package.json .
-COPY --chown=node:node web/package.json web/
-COPY --chown=node:node yarn.lock .
-
-RUN mkdir -p /home/node/.yarn/berry/index
-RUN mkdir -p /home/node/.cache
-
-RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
- --mount=type=cache,target=/home/node/.cache,uid=1000 \
- CI=1 yarn workspaces focus web --production
-
-COPY --chown=node:node redwood.toml .
-COPY --chown=node:node graphql.config.js .
-COPY --chown=node:node .env.defaults .env.defaults
-
-COPY --chown=node:node --from=web_build /home/node/app/web/dist /home/node/app/web/dist
-
-ENV NODE_ENV=production \
- API_PROXY_TARGET=http://api:8911
-
-# We use the shell form here for variable expansion.
-CMD "node_modules/.bin/rw-web-server" "--api-proxy-target" "$API_PROXY_TARGET"
-
-# console
-# -------
-FROM base as console
-
-# To add more packages:
-#
-# ```
-# USER root
-#
-# RUN apt-get update && apt-get install -y \
-# curl
-#
-# USER node
-# ```
-
-COPY --chown=node:node api api
-COPY --chown=node:node web web
-COPY --chown=node:node scripts scripts
+ CMD [ "sh", "-c", "node_modules/.bin/rw-server api & node_modules/.bin/rw-web-server --api-proxy-target $API_PROXY_TARGET" ]
+
+ # # console
+ # # -------
+ # FROM base as console
+
+ # # To add more packages:
+ # #
+ # # ```
+ # # USER root
+ # #
+ # # RUN apt-get update && apt-get install -y \
+ # # curl
+ # #
+ # # USER node
+ # # ```
+
+ # COPY --chown=node:node api api
+ # COPY --chown=node:node web web
+ # COPY --chown=node:node scripts scripts
Built with
docker build -t gobbled-up-image -f Dockerfile .
Ran with
docker run -d \
-p 8910:8910 \
-p 8911:8911 \
-e CLERK_PUBLISHABLE_KEY=your-clerk-key \
-e MY_SECRET_KEY=your-secret-value \
-e STRIPE_SECRET_KEY=sk_test_key \
gobbled-up-image
I’m hoping this example gives enough idea to how to deal with different envs (build for web vs runtime for api).