Docker a gagné en popularité ces dernières années pour permettre de placer des applications dans des conteneurs. Ces conteneurs peuvent être déployés dans n'importe quel environnement et fonctionneront de la même manière dans chacun d'eux, offrant un comportement uniforme quelle que soit la plateforme sur laquelle l'application s'exécute. Ces conteneurs utilisent des images, qui sont une copie ou un instantané compressé de l'application. En les plaçant dans un conteneur, ils sont affichés exactement tels qu'ils sont. C'est l'une de ces technologies dont certains avaient désespérément besoin, tandis que d'autres ne réalisent pas qu'ils en ont besoin jusqu'à ce qu'ils en entendent parler.
De son côté, Next.js est le framework React le plus populaire. Comme toute autre application JavaScript utilisant un bundler tel que webpack ou Vite, pour la production, une version compilée du projet est utilisée. C'est ce qu'on appelle la construction. Une build vise à fournir la quantité minimale de code nécessaire pour que l'application fonctionne de la même manière qu'en développement. Cela garantit que les fichiers JavaScript sont très légers, permettant au navigateur de les récupérer et de les interpréter dans les plus brefs délais pour restituer l'interface utilisateur ou effectuer toutes les tâches requises par l'application. "
Next.js, en particulier, propose une version qui réduit encore davantage la taille du build : le Standalone Build. Si nous utilisons Docker pour créer une image pour notre application Next.js, nous pouvons facilement déployer cette excellente application que nous avons créée dans n'importe quel environnement sans nous soucier de la compatibilité ou des configurations supplémentaires. Dans cet article, nous verrons comment y parvenir.
Dans mon cas, j'aime utiliser pnpm pour réduire la taille du disque du dossier node_modules. Par conséquent, l'exemple de l'image Docker Next.js utilise ce gestionnaire de packages, mais vous pouvez effectuer de légers ajustements pour utiliser npm ou Yarn si vous préférez.
Dans le fichier next.config.js, nous devons spécifier que le type de build résultant sera autonome lorsque l'application sera compilée pour la production. Pour cela, nous devons inclure les éléments suivants :
/** @type {import('next').NextConfig} */ const nextConfig = { output: "standalone" }; export default nextConfig;
De cette façon, la sortie de l'application sera de type autonome.
Le fichier qui représente notre image Docker est le Dockerfile. Généralement, ce fichier est placé à la racine du projet. Créons-le étape par étape.
Chaque image Docker part d'une image de base. Dans ce cas, tout projet JavaScript qui exécute un serveur aura besoin d'un moteur d'exécution tel que Node.js. Nous prendrons comme base l'image Docker d'une version Node.js compatible avec notre projet. Dans mon cas, j'aime utiliser la version Alpine des images, car elle est plus légère. Il faut cependant vérifier qu'il n'y a pas de problème de compatibilité lors de la construction de l'image, sinon, il faudra utiliser la version "non-Alpine" de l'image. Pour cet exemple, j'utilise l'image node:22.6.0-alpine3.19 comme base.
/** @type {import('next').NextConfig} */ const nextConfig = { output: "standalone" }; export default nextConfig;
On place un alias pour le recycler dans les différentes étapes ou étapes de l'image.
L'étape suivante consiste à installer les dépendances. Dans ce cas, une seule dépendance système est requise : libc6-compat. Ici, il est mentionné pourquoi.
FROM node:22.6.0-alpine3.19 AS base
Comme pnpm n'est pas inclus par défaut dans Node.js, il est nécessaire de l'activer et de définir les variables d'environnement pour que les packages installés puissent être mis en cache.
FROM base AS build-deps RUN apk add --no-cache libc6-compat
Ensuite, nous devons définir le répertoire de travail pour avoir une séparation claire entre les dossiers système et le dossier d'application. Dans ce cas, nous utilisons /app.
ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN corepack enable RUN corepack prepare pnpm@latest --activate
Nous devons maintenant copier les fichiers contenant les informations sur les dépendances du projet et les installer.
WORKDIR /app
Les arguments --frozen-lockfile et --prefer-frozen-lockfile sont utilisés pour respecter les versions spécifiées dans le fichier de verrouillage de pnpm.
Pour terminer cette étape, la bibliothèque Sharp est ajoutée. Ceci est nécessaire pour optimiser les images dans un environnement de production dans Next.js.
COPY package.json pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile --prefer-frozen-lockfile
La scène complète ressemble à ceci :
RUN pnpm add sharp
L'étape suivante consiste à compiler l'application Next.js. C'est là que réside la clé pour faire fonctionner l'image, car le reste du Dockerfile n'est rien de différent ou que vous ne pouvez trouver dans aucun autre exemple. A ce stade, il est nécessaire de passer comme arguments de build les variables d'environnement utilisées dans le projet et de les définir avant de générer le build.
En effet, comme les applications fonctionnent à deux moments, au moment de la construction et au moment de l'exécution, si les variables d'environnement ne sont pas disponibles au moment de l'exécution, tous les actifs statiques qui les utilisent n'auront pas de valeur pour elles. et l'application ne fonctionnera pas correctement. Dans cet exemple, trois variables d'environnement sont utilisées : NEXT_PUBLIC_BACKEND_URL, FRONTEND_URL et JWT_SECRET.
FROM base AS build-deps RUN apk add --no-cache libc6-compat ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN corepack enable RUN corepack prepare pnpm@latest --activate WORKDIR /app COPY package.json pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile --prefer-frozen-lockfile RUN pnpm add sharp
Ensuite, pnpm est activé, le répertoire de travail est défini, tous les fichiers de l'application sont copiés et le build est généré.
FROM base AS builder ARG NEXT_PUBLIC_BACKEND_URL ENV NEXT_PUBLIC_BACKEND_URL=$NEXT_PUBLIC_BACKEND_URL ARG FRONTEND_URL ENV FRONTEND_URL=$FRONTEND_URL ARG JWT_SECRET ENV JWT_SECRET=$JWT_SECRET
La scène complète ressemble à ceci :
RUN corepack enable RUN corepack prepare pnpm@latest --activate WORKDIR /app COPY --from=build-deps /app/node_modules ./node_modules COPY . . RUN pnpm build
La dernière étape consiste à exécuter l'application. Pour ce faire, nous définissons d'abord l'environnement de production Node :
/** @type {import('next').NextConfig} */ const nextConfig = { output: "standalone" }; export default nextConfig;
Par préférence personnelle, la télémétrie Next.js est désactivée. Autrement dit, nous n'envoyons essentiellement pas nos données d'application à Vercel pour améliorer Next.js via un diagnostic d'erreur et des mesures d'utilisation.
FROM node:22.6.0-alpine3.19 AS base
De plus, à titre de bonne pratique, il est recommandé d'utiliser un utilisateur non root dans les images Docker. Cela évite par exemple les failles de sécurité au cas où le conteneur aurait accès au réseau hôte. Pour ce faire, un groupe nodejs et un utilisateur nextjs sont ajoutés et se voient attribuer la propriété de dossier .next.
FROM base AS build-deps RUN apk add --no-cache libc6-compat
Ensuite, les fichiers générés par la version autonome sont copiés pour créer la même structure que la version par défaut de Next.js.
ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN corepack enable RUN corepack prepare pnpm@latest --activate
Puisque nous avons créé l'utilisateur nextjs, nous devons préciser que ce sera l'utilisateur à utiliser.
WORKDIR /app
De même, il est nécessaire de préciser le port exposé du conteneur, ainsi que le port du nœud et le nom d'hôte qui sera utilisé, qui sera 0.0.0.0 puisque nous ne connaissons pas l'adresse exacte.
COPY package.json pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile --prefer-frozen-lockfile
Ensuite, les variables d'environnement pour le runtime de l'application sont spécifiées à partir des arguments de construction.
RUN pnpm add sharp
Les variables d'environnement spécifiées dans un fichier docker-compose.yml peuvent être utilisées, ainsi que lors de l'exécution du conteneur, cependant, cela n'aurait pas de sens que les variables d'environnement dans ce contexte soient différentes au moment de la construction et de l'exécution. .
Enfin, nous exécutons le serveur.
FROM base AS build-deps RUN apk add --no-cache libc6-compat ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN corepack enable RUN corepack prepare pnpm@latest --activate WORKDIR /app COPY package.json pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile --prefer-frozen-lockfile RUN pnpm add sharp
Le Dockerfile complet ressemble à ceci :
FROM base AS builder ARG NEXT_PUBLIC_BACKEND_URL ENV NEXT_PUBLIC_BACKEND_URL=$NEXT_PUBLIC_BACKEND_URL ARG FRONTEND_URL ENV FRONTEND_URL=$FRONTEND_URL ARG JWT_SECRET ENV JWT_SECRET=$JWT_SECRET
Vous pouvez également trouver le fichier dans cet essentiel.
Créer une image Docker pour une application Next.js peut être intimidant au début en raison de toutes les considérations que nous devons prendre en compte. De plus, il existe une croyance populaire selon laquelle l’auto-hébergement d’une application Next.js, c’est-à-dire. e., en dehors de Vercel, c'est compliqué. Ce n'est pas le cas. En comprenant les éléments clés, c'est en fait simple.
J'espère qu'avec ces informations, vous pourrez dockeriser votre application Next.js sans problème. Et vous connaissez le principe, si vous avez des questions ou souhaitez partager quelque chose, laissez-le dans les commentaires :)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!