web-dev-qa-db-fra.com

Comment créer une image Docker à partir d'un projet nodejs dans un monorepo avec des espaces de travail de fil

Nous étudions actuellement CI/CD avec notre équipe pour notre site Web. Nous nous sommes récemment également adaptés à une structure monorepo car cela permet de garder nos dépendances et notre aperçu beaucoup plus faciles. Actuellement, les tests, etc. sont prêts pour le CI, mais je suis maintenant sur le déploiement. Je voudrais créer des images de docker des packages nécessaires.

Choses que j'ai considérées:

1) Tirez l'intégralité du monorepo dans le projet Docker, mais l'exécution d'une installation de fil dans notre projet entraîne une taille totale du projet d'environ 700 Mo, principalement en raison de notre application native React qui ne devrait même pas avoir d'image Docker. Cela devrait également entraîner un long temps de tirage d'image à chaque fois que nous devons déployer une nouvelle version

2) Regroupez mes projets d'une manière ou d'une autre. Avec notre interface, nous avons une configuration de travail qui devrait être correcte. Mais j'ai juste essayé d'ajouter webpack à notre API express et je me suis retrouvé avec une erreur dans mon bundle à cause de ce problème: https://github.com/mapbox/node-pre-gyp/issues/308 =

3) J'ai essayé d'exécuter Yarn Install uniquement à l'intérieur du projet requis, mais cela installera toujours mes node_modules pour tous mes projets.

4) Exécutez le package npm: pkg . Il en résulte un fichier unique prêt à fonctionner sur un certain système avec une certaine version de nœud. Cela fonctionne, mais je ne sais pas dans quelle mesure cela gérera les erreurs et les plantages.

5) Une autre solution pourrait être de copier le projet hors de l'espace de travail et d'exécuter une installation de fil dessus. Le problème avec cela est que l'utilisation des espaces de travail de fil (dépendances implicitement liées) est aussi bonne que disparue. Je devrais ajouter explicitement mes autres dépendances d'espace de travail. Une possibilité consiste à les référencer à partir d'un certain hachage de validation, que je vais tester en ce moment. (EDIT: vous ne pouvez pas référencer un sous-répertoire comme un paquet de fils, il semble)

6) ???

J'aimerais savoir s'il me manque une option pour n'avoir que les node_modules nécessaires pour un certain projet afin que je puisse garder mes images docker petites.

20
33Fraise33

J'ai travaillé sur un projet suivant une structure similaire à la vôtre, il ressemblait à:

project
├── package.json
├── packages
│   ├── package1
│   │   ├── package.json
│   │   └── src
│   ├── package2
│   │   ├── package.json
│   │   └── src
│   └── package3
│       ├── package.json
│       └── src
├── services
│   ├── service1
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   └── src
│   └── service2
│       ├── Dockerfile
│       ├── package.json
│       └── src
└── yarn.lock

Le dossier services/ Contient un service par sous-dossier. Chaque service est écrit dans node.js et possède son propre package.json et Dockerfile. Il s'agit généralement d'un serveur Web ou d'une API REST basée sur Express.

Le dossier packages/ Contient tous les packages qui ne sont pas des services, généralement des bibliothèques internes.

Un service peut dépendre d'un ou de plusieurs packages, mais pas d'un autre service. Un package peut dépendre d'un autre package, mais pas d'un service.

Le package.json principal (celui du dossier racine du projet) ne contient que quelques devDependencies, comme eslint, le lanceur de test, etc.

Un individu Dockerfile ressemble à ceci, en supposant que service1 Dépend à la fois de package1 Et package3:

FROM node:8.12.0-Alpine AS base

WORKDIR /project

FROM base AS dependencies

# We only copy the dependencies we need
COPY packages/package1 packages/package1
COPY packages/package3 packages/package3

COPY services/services1 services/services1

# The global package.json only contains build dependencies
COPY package.json .

COPY yarn.lock .

RUN yarn install --production --pure-lockfile --non-interactive --cache-folder ./ycache; rm -rf ./ycache

Les Dockerfile que j'ai utilisés étaient plus compliqués, car ils devaient construire les sous-packages, exécuter les tests, etc. Mais vous devriez avoir l'idée avec cet exemple.

Comme vous pouvez le voir, l'astuce consistait à ne copier que les packages nécessaires à un service spécifique. Le fichier yarn.lock Contient une liste de package @ version avec la version exacte et les dépendances résolues. Pour le copier sans tous les sous-packages n'est pas un problème, Yarn utilisera la version résolue là lors de l'installation des dépendances des packages inclus.

Dans votre cas, le projet react-native ne fera jamais partie d'aucun Dockerfile, car il est la dépendance d'aucun des services, économisant ainsi beaucoup d'espace.

Par souci de concision, j'ai omis beaucoup de détails dans cette réponse, n'hésitez pas à demander des précisions dans le commentaire si quelque chose n'est pas vraiment clair.

4

Après beaucoup d'essais et d'erreurs, j'ai constaté qu'en utilisant cette utilisation prudente du fichier .dockerignore est un excellent moyen de contrôler votre image finale. Cela fonctionne très bien lors de l'exécution sous un monorepo pour exclure les "autres" packages.

Pour chaque package, nous avons un fichier dockerignore nommé similaire qui remplace le fichier live .dockerignore juste avant la génération.

par exemple., cp admin.dockerignore .dockerignore

Voici un exemple de admin.dockerignore. Noter la * en haut de ce fichier qui signifie "tout ignorer". Le ! le préfixe signifie "ne pas ignorer", c'est-à-dire conserver. La combinaison signifie ignorer tout sauf les fichiers spécifiés.

*
# Build specific keep
!packages/admin

# Common Keep
!*.json
!yarn.lock
!.yarnrc
!packages/common

**/.circleci
**/.editorconfig
**/.dockerignore
**/.git
**/.DS_Store
**/.vscode
**/node_modules
0
Simeon

Nous avons récemment mis nos services backend à un monorepo et c'était l'un des quelques points que nous devions résoudre. Le fil n'a rien qui pourrait nous aider à cet égard, nous avons donc dû chercher ailleurs.

Nous avons d'abord essayé @ zeit/ncc , il y a eu quelques problèmes mais nous avons finalement réussi à obtenir les versions finales. Il produit un gros fichier qui comprend tout votre code et aussi tout votre code de dépendances. Ça avait l'air super. Je n'ai dû copier sur l'image docker que quelques fichiers (js, cartes sources, actifs statiques). Les images étaient beaucoup plus petites et l'application fonctionnait. MAIS la consommation de mémoire d'exécution a beaucoup augmenté. Au lieu de ~ 70 Mo, le conteneur en cours d'exécution a consommé ~ 250 Mo. Je ne sais pas si nous avons fait quelque chose de mal, mais je n'ai trouvé aucune solution et il n'y en a qu'une issue le mentionnant. Je suppose que Node.js charge les analyses et charge tout le code du bundle même si la majeure partie n'est jamais utilisée.

Tout ce dont nous avions besoin est de séparer chacune des dépendances de production des packages pour créer une image de docker mince. Il semble que ce ne soit pas si simple à faire, mais nous avons trouvé un outil après tout.

Nous utilisons maintenant fleggal/monopack . Il regroupe notre code avec Webpack et le transpile Babel. Donc, il produit également un bundle de fichiers mais il ne contient pas toutes les dépendances, juste notre code. Cette étape est quelque chose dont nous n'avons pas vraiment besoin, mais cela ne nous dérange pas qu'elle soit là. Pour nous, la partie importante est: Monopack copie uniquement l'arbre de dépendance de production du package dans les modules dist/bundled node_modules. C'est exactement ce dont nous avions besoin. Les images Docker ont désormais 100 Mo à 150 Mo au lieu de 700 Mo.

Il existe un moyen plus simple. Si vous n'avez que quelques modules npm vraiment gros dans votre node_modules vous pouvez utiliser nohoist dans votre racine package.json. De cette façon, yarn conserve ces modules dans le package local node_modules et il ne doit pas être copié sur les images Docker de tous les autres services.

par exemple.:

"nohoist": [
  "**/puppeteer",
  "**/puppeteer/**",
  "**/aws-sdk",
  "**/aws-sdk/**"
]
0
Pavel