I am trying to run a container on docker, i have a Dockerfile
for building image, and compose.yml
for multi-container configurations, note that I am using Next.js to develop my app.
Dockerfile
# First Stage is used to install the dependencies from the host machine app to the image /app directory
FROM node:22-alpine AS initiate
# set the working directory in the container to /app
WORKDIR /app
# copy package.json from the host machine to the /app directory in the image
COPY package*.json ./
RUN --mount=type=secret,id=CONNECTION_STRING \
--mount=type=secret,id=EMAIL_SERVER_HOST \
--mount=type=secret,id=EMAIL_SERVER_USER \
--mount=type=secret,id=EMAIL_SERVER_PASSWORD \
--mount=type=secret,id=EMAIL_FROM \
--mount=type=secret,id=NEXTAUTH_URL \
--mount=type=secret,id=NEXTAUTH_SECRET \
export CONNECTION_STRING="$(cat /run/secrets/CONNECTION_STRING)" && \
export EMAIL_SERVER_HOST="$(cat /run/secrets/EMAIL_SERVER_HOST)" && \
export EMAIL_SERVER_USER="$(cat /run/secrets/EMAIL_SERVER_USER)" && \
export EMAIL_SERVER_PASSWORD="$(cat /run/secrets/EMAIL_SERVER_PASSWORD)" && \
export EMAIL_FROM="$(cat /run/secrets/EMAIL_FROM)" && \
export NEXTAUTH_URL="$(cat /run/secrets/NEXTAUTH_URL)" && \
export NEXTAUTH_SECRET="$(cat /run/secrets/NEXTAUTH_SECRET)" && \
npm ci
# 2nd Stage is used to build the app
FROM initiate AS build
COPY . .
# copy the rest of application from the host machine to the /app directory in the image to build the app
RUN --mount=type=secret,id=CONNECTION_STRING \
--mount=type=secret,id=EMAIL_SERVER_HOST \
--mount=type=secret,id=EMAIL_SERVER_USER \
--mount=type=secret,id=EMAIL_SERVER_PASSWORD \
--mount=type=secret,id=EMAIL_FROM \
--mount=type=secret,id=NEXTAUTH_URL \
--mount=type=secret,id=NEXTAUTH_SECRET \
export CONNECTION_STRING="$(cat /run/secrets/CONNECTION_STRING)" && \
export EMAIL_SERVER_HOST="$(cat /run/secrets/EMAIL_SERVER_HOST)" && \
export EMAIL_SERVER_USER="$(cat /run/secrets/EMAIL_SERVER_USER)" && \
export EMAIL_SERVER_PASSWORD="$(cat /run/secrets/EMAIL_SERVER_PASSWORD)" && \
export EMAIL_FROM="$(cat /run/secrets/EMAIL_FROM)" && \
export NEXTAUTH_URL="$(cat /run/secrets/NEXTAUTH_URL)" && \
export NEXTAUTH_SECRET="$(cat /run/secrets/NEXTAUTH_SECRET)" && \
npm run build
# 3rd Stage is used to run the app
FROM initiate AS run
RUN addgroup --system --gid 1001 nonroot
RUN adduser --system --uid 1001 runner
# Create a non-root user to run the app and assign it to the nonroot group
USER runner
# Switch to the user runner
COPY --from=build /public ./public
COPY --from=build --chown=runner:nonroot /.next/standalone ./
COPY --from=build --chown=runner:nonroot /.next/static ./.next/static
EXPOSE 3000
CMD ["npm","run","start"]
compose.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
secrets:
- EMAIL_SERVER_HOST
- EMAIL_SERVER_PORT
- EMAIL_SERVER_USER
- EMAIL_SERVER_PASSWORD
- EMAIL_FROM
- CONNECTION_STRING
- NEXTAUTH_SECRET
- NEXTAUTH_URL
environment:
- PROD='1'
ports:
- "3000:3000"
secrets:
- CONNECTION_STRING #providing secrets after the image build because they are needed for access to the container
- EMAIL_FROM
- EMAIL_SERVER_HOST
- EMAIL_SERVER_PASSWORD
- EMAIL_SERVER_PORT
- EMAIL_SERVER_USER
- NEXTAUTH_SECRET
- NEXTAUTH_URL
secrets:
EMAIL_SERVER_HOST:
file: ./run/secrets/EMAIL_SERVER_HOST
EMAIL_SERVER_PORT:
file: ./run/secrets/EMAIL_SERVER_PORT
EMAIL_SERVER_USER:
file: ./run/secrets/EMAIL_SERVER_USER
EMAIL_SERVER_PASSWORD:
file: ./run/secrets/EMAIL_SERVER_PASSWORD
EMAIL_FROM:
file: ./run/secrets/EMAIL_FROM
CONNECTION_STRING:
file: ./run/secrets/CONNECTION_STRING
NEXTAUTH_SECRET:
file: ./run/secrets/NEXTAUTH_SECRET
NEXTAUTH_URL:
file: ./run/secrets/NEXTAUTH_URL
the secrets in host machine are stored in run/secrets/
folder, and this run
folder is in the project root.
and the way I access those secrets when PROD
is on is like this:
const getVars = async ()=>{
if((process!.env!.PROD!)=='0'){
return {
host: process.env!.EMAIL_SERVER_HOST!,
port: process.env!.EMAIL_SERVER_PORT!,
user: process.env!.EMAIL_SERVER_USER!,
pass: process.env!.EMAIL_SERVER_PASSWORD!,
from:process.env!.EMAIL_FROM!
}
}
return{
host: await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_SERVER_HOST'),{encoding:'utf-8'}),
port: await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_SERVER_PORT'),{encoding:'utf-8'}),
user:await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_SERVER_USER'),{encoding:'utf-8'}),
pass:await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_SERVER_PASSWORD'),{encoding:'utf-8'}),
from:await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_FROM'),{encoding:'utf-8'}) as unknown as string
}
}
but I get error during the run of the build layer:
> [build 2/2] RUN --mount=type=secret,id=CONNECTION_STRING --mount=type=secret,id=EMAIL_SERVER_HOST --mount=type=secret,id=EMAIL_SERVER_USER --mount=type=secret,id=EMAIL_SERVER_PASSWORD --mount=type=secret,id=EMAIL_FROM --mount=type=secret,id=NEXTAUTH_URL --mount=type=secret,id=NEXTAUTH_SECRET export CONNECTION_STRING="$(cat /run/secrets/CONNECTION_STRING)" && export EMAIL_SERVER_HOST="$(cat /run/secrets/EMAIL_SERVER_HOST)" && export EMAIL_SERVER_USER="$(cat /run/secrets/EMAIL_SERVER_USER)" && export EMAIL_SERVER_PASSWORD="$(cat /run/secrets/EMAIL_SERVER_PASSWORD)" && export EMAIL_FROM="$(cat /run/secrets/EMAIL_FROM)" && export NEXTAUTH_URL="$(cat /run/secrets/NEXTAUTH_URL)" && export NEXTAUTH_SECRET="$(cat /run/secrets/NEXTAUTH_SECRET)" && npm run build:
0.560
0.560 > myportfolio@0.1.0 build
0.560 > next build
0.560
1.523 Attention: Next.js now collects completely anonymous telemetry regarding usage.
1.523 This information is used to shape Next.js' roadmap and prioritize features.
1.523 You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
1.523 https://nextjs.org/telemetry
1.523
1.619 ▲ Next.js 14.2.17
1.619
1.718 Creating an optimized production build ...
119.7 ✓ Compiled successfully
119.7 Linting and checking validity of types ...
127.0
127.0 ./src/app/blog/clientComp.tsx
127.0 29:21 Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
127.0 29:21 Warning: img elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
127.0
127.0 ./src/app/components/blogs/blogs.tsx
127.0 63:25 Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
127.0
127.0 ./src/app/components/experience/experience.tsx
127.0 23:9 Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
127.0
127.0 info - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules
134.7 Collecting page data ...
137.1 Error: ENOENT: no such file or directory, open '/app/run/secrets/EMAIL_SERVER_HOST'
137.1 at async open (node:internal/fs/promises:639:25)
137.1 at async readFile (node:internal/fs/promises:1243:14)
137.1 at async m (/app/.next/server/app/api/auth/[...nextauth]/route.js:67:84167)
137.1 at async g (/app/.next/server/app/api/auth/[...nextauth]/route.js:67:84688)
137.1 at async /app/.next/server/app/api/auth/[...nextauth]/route.js:67:84949 {
137.1 errno: -2,
137.1 code: 'ENOENT',
137.1 syscall: 'open',
137.1 path: '/app/run/secrets/EMAIL_SERVER_HOST'
137.1 }
137.1
137.1 > Build error occurred
137.1 Error: Failed to collect page data for /api/auth/[...nextauth]
137.1 at /app/node_modules/next/dist/build/utils.js:1268:15 {
137.1 type: 'Error'
137.1 }
------
Dockerfile:34
--------------------
33 | # copy the rest of application from the host machine to the /app directory in the image to build the app
34 | >>> RUN --mount=type=secret,id=CONNECTION_STRING \
35 | >>> --mount=type=secret,id=EMAIL_SERVER_HOST \
36 | >>> --mount=type=secret,id=EMAIL_SERVER_USER \
37 | >>> --mount=type=secret,id=EMAIL_SERVER_PASSWORD \
38 | >>> --mount=type=secret,id=EMAIL_FROM \
39 | >>> --mount=type=secret,id=NEXTAUTH_URL \
40 | >>> --mount=type=secret,id=NEXTAUTH_SECRET \
41 | >>> export CONNECTION_STRING="$(cat /run/secrets/CONNECTION_STRING)" && \
42 | >>> export EMAIL_SERVER_HOST="$(cat /run/secrets/EMAIL_SERVER_HOST)" && \
43 | >>> export EMAIL_SERVER_USER="$(cat /run/secrets/EMAIL_SERVER_USER)" && \
44 | >>> export EMAIL_SERVER_PASSWORD="$(cat /run/secrets/EMAIL_SERVER_PASSWORD)" && \
45 | >>> export EMAIL_FROM="$(cat /run/secrets/EMAIL_FROM)" && \
46 | >>> export NEXTAUTH_URL="$(cat /run/secrets/NEXTAUTH_URL)" && \
47 | >>> export NEXTAUTH_SECRET="$(cat /run/secrets/NEXTAUTH_SECRET)" && \
48 | >>> npm run build
49 |
--------------------
failed to solve: process "/bin/sh -c export CONNECTION_STRING=\"$(cat /run/secrets/CONNECTION_STRING)\" && export EMAIL_SERVER_HOST=\"$(cat /run/secrets/EMAIL_SERVER_HOST)\" && export EMAIL_SERVER_USER=\"$(cat /run/secrets/EMAIL_SERVER_USER)\" && export EMAIL_SERVER_PASSWORD=\"$(cat /run/secrets/EMAIL_SERVER_PASSWORD)\" && export EMAIL_FROM=\"$(cat /run/secrets/EMAIL_FROM)\" && export NEXTAUTH_URL=\"$(cat /run/secrets/NEXTAUTH_URL)\" && export NEXTAUTH_SECRET=\"$(cat /run/secrets/NEXTAUTH_SECRET)\" && npm run build" did not complete successfully: exit code: 1
a screenshot of run/secrets
folder:
The folder is on the project root.
You prepend the working directory to the secret file names in your Javascript which causes it to look for the files in /app/run/secrets/
instead of /run/secrets
.
Instead of
host: await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_SERVER_HOST'),{encoding:'utf-8'}),
port: await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_SERVER_PORT'),{encoding:'utf-8'}),
user:await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_SERVER_USER'),{encoding:'utf-8'}),
pass:await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_SERVER_PASSWORD'),{encoding:'utf-8'}),
from:await readFile(path.join(process.cwd(), 'run/secrets/EMAIL_FROM'),{encoding:'utf-8'}) as unknown as string
use
host: await readFile('/run/secrets/EMAIL_SERVER_HOST',{encoding:'utf-8'}),
port: await readFile('/run/secrets/EMAIL_SERVER_PORT',{encoding:'utf-8'}),
user:await readFile('/run/secrets/EMAIL_SERVER_USER',{encoding:'utf-8'}),
pass:await readFile('/run/secrets/EMAIL_SERVER_PASSWORD',{encoding:'utf-8'}),
from:await readFile('/run/secrets/EMAIL_FROM',{encoding:'utf-8'}) as unknown as string