node.js - Nextjsin dockerointi TypeScriptin kanssa
Yritän rakentaa Docker-kuvaa Nextjs-frontend (React) -sovelluksestani tuotantokäyttöä varten, ja olen tällä hetkellä jumissa TypeScript-integraation kanssa.
Tässä on Dockerfile.
FROM node:14-alpine3.14 as deps
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
EXPOSE 4500
RUN apk add --no-cache libc6-compat
RUN mkdir /app && chown -R node:node /app
WORKDIR /app
COPY --chown=node:node package.json package-lock.json ./
RUN npm ci --production && npm cache clean --force
FROM node:14-alpine3.14 as build
RUN mkdir /app && chown -R node:node /app
WORKDIR /app
ENV NODE_ENV=production
COPY --chown=node:node . ./
COPY --from=deps /app/node_modules ./node_modules
RUN npm run build
FROM node:14-alpine3.14 as prod
RUN mkdir /app && chown -R node:node /app
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=7777
COPY --from=build /app ./
USER node
CMD ["node_modules/.bin/next", "start"]
Nyt tästä seuraa virhe:
It looks like you're trying to use TypeScript but do not have the required package(s) installed.
Periaatteessa koska teen npm ci --production, se ei asenna devDependencies, joissa TypeScript on.
Etsimisen jälkeen olen tullut muutamiin ratkaisuihin.
Ratkaisu 1: Ensimmäinen on lisätä Typescript riippuvuuksiin. Vaikka on suositeltavaa, että koska Typescript on vain devDependency, sitä ei pitäisi olla tavanomaisissa riippuvuuksissa.
Ratkaisu 2: Typescriptin lisääminen komennolla npm install. Periaatteessa sama kuin ratkaisu 1. Muokkasin Dockerfilea näin:
FROM node:14-alpine3.14 as deps
COPY --chown=node:node package.json package-lock.json ./
RUN npm ci --production && npm cache clean --force
Added typescript and node types here
RUN npm install --save-dev typescript @types/node
Tässä tapauksessa koko kuvan koko tulee olemaan: 981,58 MB.
Ratkaisu 3: Yksinkertaisesti npm install tekeminen npm ci --production sijaan.
FROM node:14-alpine3.14 as deps
COPY --chown=node:node package.json package-lock.json ./
Simple npm install
RUN npm install && npm cache clean --force
Tässä tapauksessa lopetan myös kaikkien devDependenciesien asentamisen. Tässä tapauksessa kokonaiskuvan koko on: 537,32 MB.
Nyt minulla on muutama kysymys tästä.
Kysymys 1: Miksi tyypin lisääminen TypeScriptin avulla komennolla npm install --save-dev typescript @types/node Ratkaisussa 2 johtaa suurempaan tiedostokokoon verrattuna Ratkaisuun 3, jossa asennamme kaikki riippuvuudet?
Kysymys 2: Jos Ratkaisussa 3 teen npm ci npm install sijaan, kokonaiskuvan koko on 972,59 Mt. Miksi npm ci käyttö lisää kuvan kokoa? Eikö sen pitäisi vain asentaa tarkat paketit package-lock.jsonin perusteella.
Kysymys 3: Katsoin keskustelua. Pyydettiin asentamaan Typescript, vaikka se oli jo asennettu Docker-kuvaa rakennettaessa.
Se ehdotti ratkaisua monivaiheisella rakentamisella kuten tämä.
FROM gcr.io/companyX/companyX-node-base:12-alpine AS build
Copy in only the parts needed to install dependencies
(This avoids rebuilds if the package.json hasn’t changed)
COPY package.json package.lock .
Install dependencies (including dev dependencies)
RUN npm install
Copy in the rest of the project
(include node_modules in a .dockerignore file)
COPY . .
Build the project
RUN npm run build
Second stage: runtime
FROM gcr.io/companyX/companyX-node-base:12-alpine
ENV NODE_ENV=production
Again get dependencies, but this time only install
runtime dependencies
COPY package.json package.lock .
RUN npm install
Get the built application from the first stage
COPY --from=build /app/dist dist
Set runtime metadata
EXPOSE 3000
CMD [ "npm", "start" ]
CMD ["node", "dist/index.js"]
Eikö tämä ratkaisu ole huono, koska joudut tässä tapauksessa asentamaan riippuvuuksia kahdesti. Kerran build-vaiheessa ja toisen kerran runner-vaiheessa, vaikka asentaisitkin vain tuotantoriippuvuudet runner-vaiheessa.
Kokeilin tätä ratkaisua ja kuten odotettua päädyin kuvatiedoston kokoon 1,18 Gt.
Kysymys 4: Kumpi yllä olevista ratkaisuista on parempi valita? Vai onko olemassa parempi tapa tehdä tämä?
Vastaus #1
Käytä välikonttia asentaaksesi vain tuotantopaketteja
FROM node:14-alpine AS build
Disable telemetry
ENV NEXT_TELEMETRY_DISABLED 1
WORKDIR /build
Copy package and package-lock
COPY package.json package-lock.json ./
Clean install dependencies based package-lock
Note: We also install dev deps as typeScript may be needed
RUN npm ci
Copy files
Use .dockerignore to avoid copying node_modules and others folders and files
COPY . .
Build application
RUN npm run build
=======================================
Image generate dependencies production
=======================================
FROM node:14-alpine AS dependencies
Environment Production
ENV NODE_ENV production
WORKDIR /dependencies
Copy package and package-lock
COPY --from=build /build/package.json .
COPY --from=build /build/package-lock.json ./
Clean install dependencies based package-lock
RUN npm ci --production
=======================================
Image distroless final
=======================================
FROM gcr.io/distroless/nodejs:14
Mark as prod, disable telemetry, set port
ENV NODE_ENV production
ENV PORT 3000
ENV NEXT_TELEMETRY_DISABLED 1
WORKDIR /app
Copy from build
COPY --from=build /build/next.config.js .
COPY --from=build /build/public/ ./public
COPY --from=build /build/.next ./.next
COPY --from=dependencies /dependencies/node_modules ./node_modules
EXPOSE 3000
Run app command
CMD ["node_modules/.bin/next", "start"]
Vastaus #2
Tässä tapauksessa voit käyttää pohjakuvana tuotantovaiheessa kuvaa https://github.com/ryanbekhen/feserve/pkgs/container/feserve. Tämä on kuva, jonka tein perustuen etupään esiintyneisiin valituksiin. Pohjakuva on vain noin 8 Mt, joten se ei vie paljon tallennustilaa.
