Cache npm packages in Docker GitHub actions - node.js

I actually have GitHub actions that tests a nodeJS project in a Docker image (node:16-alpine). My problem is that at each run, yarn install re-installed completely all the packages. My question is: how can I cache these packages between runs ?
I've trouble doing it since the execution run in the Docker image and I could not find a solution to cache the packages. Thank you for your help!

You can use github actions cache to cache things inside your job.
If you're using a docker image separately from your job, probably you can't cache that. My suggestion, improve your workflow if you create a job for a test and need the same environment put it all in just one job with different steps.

Related

Force project to use Yarn but not npm

As a team practice, I would like to force my teammate to use yarn install/ run but not npm install/ run.
Is it possible to force a package.json 's dependency be installed only via yarn install or package.json's script be run only via yarn run?
If it cannot be done, can I at least get a warning when using npm install?
Again, this is only to align the team practice, so that reduces the possibility of error/ problem produced during dev/ops. Thanks
One of the way I can think of is CI can set a rules to detect if there is new file package-lock.json file being created, make the build fail. The developer will then realized he made a mistake since his build failed.
Alternatively you can also rely on husky pre-commit hook, which essentially runs a command to check if package-lock.json existed everytime developer trying to run git commit.

Should I use yarn workspaces on production?

Me and a coworker are working on the deploy of some APIs that have some sharedlibs in common.
The thing is, he said that workspaces shouldn't be used in production, but no reason was presented to defend that. I came with the following setup:
Set SSH Keys from the remote for pull the repository
Run yarn workspace <api-name> install for a single API
Run yarn build for ES6/Babel
Run API from dist folder. And we're done. No need for bash scripts or NPM private packages.
I see nothing wrong with your setup. Yarn Workspaces is used to simplify management tasks on your code tree (and I see install script as code). It does not really matters whether you run yarn workspace <api-name> install or cd <api-name>; ./install.sh - but the former is less error-prone.

Building image from multiple docker hub images or private repo docker

i am able to create the dockerFile where i could do the stuffs. Its like i might have 10-15 apps running for now and more to go.
my dockerFile
FROM ubuntu:16.04
RUN installing necessary softwares
The thing i am trying is installing the softwares via images too. Like for
php7.0
FROM ubuntu:16.04
FROM php:7.0-cli
RUN installing necessary softwares
So currently i am making docker file for each project and do like FROM source RUN install this and that and same thing i have to do for the rest. Lets suppose i want to change the version of php for all 10 servers. i have to open file and edit. Any good suggestion to overcome this problem?
Maybe you can use ENV variables? Like
...
ENV PHP_VERSION=7.0
RUN apt-get install php=$PHP_VERSION
...
Or maybe use templating language which is offered by tool Rocker

pre-cache node_modules in Docker container

It frustrates me that CI builds for projects which use Node tool chains such as Grunt and Gulp take quite a long time, the bulk of which is consumed by npm install.
I've tried to set up a Docker image, pre-baked with all of the node_module dependencies in the npm cache (each at the same fixed release as declared in my package.json file), but even then the build still takes a few minutes when all it really should need to do is to copy a few directories from the npm cache into my project's node_modules.
I've set cache-min to 9999999, but it still seems to take much longer than it shoul need to.
I've looked local-npm and npm_lazy but they seem over the top, and the former takes ages to install - I suspect that it's trying to download every single npm module in existence - I only need a limited number and don't need to be running a web server to serve them from within the Docker container.
...am I missing something? There must be a faster way to run a CI build...
I was able to get it to work by using .npmrc to point to the npm cache within the docker container. I would suggest you to docker exec into your container and run npm config list | grep cache to ensure that the cache is used.

Speeding up the npm install

I am trying to speed up the npm install during the build process phase. My package.json has the list of packages pretty much with locked revisions in it. I've also configured the cache directory using the command
npm config set cache /var/tmp/npm-cache --global
However, on trying to install using npm install -g --cache, I find that this step isn't reducing the time to install by just loading the packages from cache as I would expect. In fact, I doubt if it's even using the local cache to look up packages first.
Proposing two more modern approches:
1) npm ci
Use npm ci, which is available from npm version 5.7.0 (although I recommend 5.7.1 and upwards because of the broken release) - this requires package-lock.json to be present and it skips building your dependency tree off of your package.json file, respecting the already resolved dependency URLs in your lock file.
A very quick
boost for your CI/CD envs (our build time was cut down to a quarter of the original!) and/or to make sure all your developers sit on the same versions of dependencies during development (without having to hard-code strict versions in your package.json file).
Note however that npm ci removes the node_modules/ directory before installing, so it won't benefit from any caching strategies.
2) npm i --prefer-offline
Use the --prefer-offline flag with your regular npm install / npm i. With this approach, you need to make sure you've cached your node_modules/ directory between builds (in a CI/CD environment). If it fails to find packages locally with the specific version, it falls back to the network safely.
You can also add --no-audit --progress=false to reduce pre-install checks and remove the progress bar (latter is only a very slight improvement)
For pure npm solution, you may try
npm install --prefer-offline --no-audit --progress=false
Prefer offline may not be useful for the first run.
As suggested by #Daniel Serodio
You could also include your node_modules folder inside your repository but you should probably zip it first than add to repo, and while installing you can unzip it and just
npm rebuild
(which works cross platform) it is quite fast.
This would also give you the benefit of full control over all your dependencies.
Also you can set the process flag to false to increase your speed by 2x.
npm set progress=false
Read source for more info
Update:
You can also use pnpm for this
npm i -g pnpm
This basically use local cached modules (i have heard its better then YARN)
It's better to install pnpm package using the following command:
npm i -g pnpm
pnpm uses hard links and symlinks to save one version of a module only ever once on a disk. When using npm or Yarn for example, if you have 100 projects using the same version of lodash, you will have 100 copies of lodash on disk. With pnpm, lodash will be saved in a single place on the disk and a hard link will put it into the node_modules where it should be installed.
As an example I can mention that whenever you want to install the dependencies of package.json file, what you should do is simply that enter the pnpm i and it handles the other things by itself.
UPDATE: The original answer is from 2014. I wouldnt recommend checking in node_modules, as there are definitly better options around speeding up the install especially for a ci pipeline, eg. npm ci --only=production
You could also include your node_modules folder inside your repository (you are probably using git), and just npm rebuild (which works cross platform) on build/deploy processes, and is pretty fast.
This would also give you the benefit of full control over all your dependencies (I know that's what shrinkwrap usually should be used for)
Edit:
Also you can set the progress flag to false to increase your speed by at least 20%. This works only with npm#v3.x.x, and there will be hopefully fixes for that soon (see second link)
npm set progress=false
Tweet about finding
Github Issue Cause identification
As very modern solution you can start to use Docker.
Docker allows you virtualize and pre-define as image the current state of your code, including installed npm-modules and other goodies.
Once the docker image for your infrastructure/env is built locally, or retrieved from remote repository, it will be stored on the host machine, and you can spin server in seconds.
Another benefit of it is that you use same virtualized code infrastructure on any machine where you deploy your code.
Docker speeds up install/deployment processes and is widely used technology.
To start using docker is enough to (all the snippets are just mock/example for pre-setup and are not by any means most robust/elegant solution) :
1) Install docker and docker-compose using manuals and get some basic understanding of it at docker.com
2) Write Dockerfile file in root of your application
FROM node:6.9.5
RUN mkdir /usr/local/app
WORKDIR /usr/local/app
COPY package.json package.json
RUN npm install
3) create docker-compose.yml in the root of your project with such content:
version: "2"
server:
hostname: server
container_name: server
image: server
build: .
command: sh -c 'NODE_ENV=development PORT=8080 node app.js'
ports:
- "8080:8080"
volumes: #list of folders and files to use
- ${PWD}/server:/usr/local/server
- ${PWD}/app.js:/usr/local/app.js
4) To start server you will need to docker-compose up -d. To see the logs docker-compose logs -f server. If you will restart your server it will do it in seconds once it built the image already at once.
Then it will cache build layers locally so next run will take only few seconds.
I know this might be bit of a robust solution, but I am sure it is have most potential/flexibility and is widely used in industry. And while it requires some learning for anyone who did not use Docker before, in my humble oppinion, it is the best one for your problem.
Nothing helped me more than disabling antivirus (Windows Defender in my case) I got from 2:30 to 1 minute.
With npm-cache package I got to ~30 secs.
I tried to use yarn, which is very fast, but was randomly failing in my case.
We have been trying to solve this problem to speed up our deployments.
We have settled on using pac, which follows the principles in the other answers. It zips the npm modules and includues them in your repo so you don't have a million files in your commits and code reviews and you can just unzip/rebuild for the target machine.
https://www.npmjs.com/package/pac

Resources