npm command not found error while running docker container - node.js

I am trying some something out with gitlab-runner image,
FROM gitlab/gitlab-runner:alpine
WORKDIR /app
COPY . /app
RUN apk add yarn && yarn install
RUN yarn --version # this layer prints 1.16.0
RUN ng build --prod
EXPOSE 3000
CMD ["yarn", "run", "start"]
above is the docker file I have created
docker build -t runner:1 .
I was able to build the image successfully
docker run -p 3000:3000 runner:1
but when I try to run the container it gives me below error
`*FATAL: Command yarn not found.*`
not sure about the behavior, if it is able to install yarn (apk add yarn) in base images and install the dependencies using yarn install then how it is not able to find the yarn command while running the container? Where I am going wrong.
Also at which directory yarn is installed in the alpine ?
I know it is not an efficient docker file, but I am trying to run the container first before optimizing it.

It outputs the version. It means the yarn is installed already. You could find the path the same as you find the version.
RUN which yarn
Step 6/10 : RUN which yarn
---> Running in 0f633b81f2ed
/usr/bin/yarn
We can see the /usr/bin/ has added to PATH.
Step 7/11 : RUN echo $PATH
---> Running in fc3f40b6bfd9
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
But I couldn't figure out why isn't reading yarn from the PATH.
So, we have set the PATH explicitly in our Dockerfile.
ENV PATH=${PATH}
But still, the issue persists. Now we have to separate yarn and commands as ENTRYPOINT and CMD respectively in the Dockerfile.
ENTRYPOINT ["yarn"]
CMD ["run", "start"]
Updated Dockerfile
FROM gitlab/gitlab-runner:alpine
ENV PATH=${PATH}
WORKDIR /app
COPY . /app
RUN apk add yarn && yarn install
RUN yarn --version # this layer prints 1.16.0
RUN ng build --prod
EXPOSE 3000
ENTRYPOINT ["yarn"]
CMD ["run", "start"]
---
$ docker run -p 3000:3000 harik8/yarn:latest
yarn run v1.16.0
error Couldn't find a package.json file in "/app"
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
The behaviours of the base image look unusual. It'd be better to go through it.

To build your app you shouldn't use gitlab-runner image, but a 'node' one.
Gilab-runner image is for running a gitlab agent which can be connected to docker engine and spawn the node container in which you will execute your build, in your case a docker image build.
To use gilab you need to prepare a gitlab-ci file where you will define what steps and which 'services' you need to do your build.
Tl;dr: change base image to node:latest and as a entirely separate work setup gitlab runner.
However if your aim is to have your application to extend gitlab runner, try docker multistage builds.
First, use node:latest image to build your app, and then copy the build output into gitlab-runner.
Runtime images such as gitlab-runner are stripped from build tools like yarn or npm, that's why your image fails. Main goal is to keep runtime images as small as possible and sdk's are not needed and sometimes dangerous when it comes to production-level work.

Related

Jest Unit Testing in Docker Container

I am trying to move my tests to my docker image build stage but it seems to ignore my test build at all and just skip it when I build the image.
What can be the problem?
# Base build
FROM node:16.13 AS build
RUN mkdir /app
WORKDIR /app
ADD package*.json ./
RUN npm i -g npm#6.14.15
RUN npm i --production
COPY . .
RUN npm run build
# Clean
RUN npm prune --production
RUN npm install -g node-prune
RUN node-prune
# Test
FROM build AS test
RUN npm i -g npm#6.14.15
RUN npm i -D jest typescript
RUN npm i -D ts-jest #types/jest
RUN npm i -D #shelf/jest-mongodb
RUN npx jest
# Release
FROM node:16.13-alpine
RUN mkdir /app
WORKDIR /app
COPY --from=build /app/dist ./dist/
COPY --from=build /app/node_modules ./node_modules/
COPY --from=build /app/package.json ./
CMD npm start
Above you can see my Dockerfile where I am preparing the build, then plan to have tests and after that, I am making my release image.
I've already been playing around with that for hours; I cleared cache, made tweaks with the order in the file) but it didn't help. It keeps ignoring my test build.
Any hint of that and in general on my Dockerfile is welcomed
Docker internally has two different systems to build images. Newer Dockers default to a newer system called BuildKit. One of the major differences is the way the two systems handle multi-stage builds: the older system just runs all of the build stages until the end, but BuildKit figures out that the final stage COPY --from=build but doesn't use anything from the test stage, and just skips it.
I wouldn't run these tests in a Dockerfile (since it doesn't produce a runnable artifact) or in Docker at all. I'd probably run them in my host-based development environment, before building a Docker image:
# On the host
npm install # devDependencies include all test dependencies
npm run tests # locally
# repeat until the tests pass (without involving a container)
# Build the image _after_ the tests pass
docker build -t myapp .
docker build also has a --target option to name a specific stage so you could tell Docker to "build the test image", but you'd just immediately delete it. This is where I don't think Docker quite makes sense as a test runner.
docker build -t delete-me --target test
docker build -t my-app .
docker rmi delete-me
Your Dockerfile also installs a MongoDB test helper. If the test depends on a live database rather than a mock implementation, the other thing to be aware of here is that code in a Dockerfile can never connect to other containers. You have to run this test from somewhere else in this case.

The Next.js app does not work well after creating the image

I have a problem after creating a docker image.
If I build applications without Docker (npm run build, npm start), everything works correctly. Screenshots below.
Please suggest how to fix the problem
Dockerfile:
FROM node:alpine
RUN apk add --no-cache libc6-compat
RUN mkdir /brahhouse
WORKDIR /brahhouse
COPY ./package*.json /brahhouse
RUN npm install
COPY . /brahhouse
RUN npm run build
CMD ["npm", "start"]
I build docker image with command:
docker build -t brahouse .
I run docker image with command:
docker run -p 3000:3000 brahouse
Screenshots:
App without Docker
App in Docker Images
Problem solved
Thank you brc-dd
Solution:
Editing tailwind.config.js (purge -> content) Set the correct paths for components, pages and other folders used by tailwind-css

Why official manual docker example does not work

I'm new to docker, so I have visited the https://www.docker.com/101-tutorial tutorial and executed, folowing their advice:
docker run -dp 80:80 docker/getting-started
This let me read the manual via http:/localhost:80. This works all right and I'm presented with the official docker manual. I follow it. They say to prepare a Dockerfile like this:
FROM node:12-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
which i did. I built the image: docker build -t getting-started . and tried to run it, docker run -dp 3000:3000 getting-started, but with no success. I checked with docker ps that this did not work. After some experimentation (with some "debugging" via an interactive docker launch, with /bin/sh as the initial command) I produced this Dockerfile, which works:
FROM node:alpine
WORKDIR /app
COPY . .
RUN yarn install --production
RUN yarn add express
RUN yarn add sqlite3
CMD ["node", "app/src/index.js"]
I'm quite impressed that without much knowledge about docker, and with absolutely no knowledge about node.js and Alpine Linux, I managed to fix the problem myself. Now I would like to understand what's going on here.
My question is as in the title: why the original instructions from the official manual fail on my computer? Why do I have to install extra libraries and why my working files go to /app/app rather than just /app?
My environment:
> cat /etc/lsb-release
DISTRIB_ID=ManjaroLinux
DISTRIB_RELEASE=20.2
DISTRIB_CODENAME=Nibia
DISTRIB_DESCRIPTION="Manjaro Linux"
> docker --version
Docker version 19.03.13-ce, build 4484c46d9d
My experiment with an interactive container:
> docker run -it my_image /bin/sh
/app # ls
Dockerfile app node_modules package.json yarn.lock
/app # ls app
package.json spec src yarn.lock

Docker / NodeJS: "exec: \"-d\": executable file not found in $PATH"

I am having a problem running Docker container after upgrading from NodeJS 8.2 to 9.1. This is the message I am getting.
I used the Dockerfile I found in Docker Hub but got an error of not being able to find package.json. So I commented it out and use the one I found on NodeJS website.
Below is the Docker File:
Dockerfile
FROM node:9.1.0
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ONBUILD ARG NODE_ENV
ONBUILD ENV NODE_ENV $NODE_ENV
ONBUILD COPY package*.json ./
ONBUILD RUN npm install && npm cache clean --force
ONBUILD COPY . /usr/src/app
CMD [ "npm", "start" ]
I would appreciate help from more experienced users.
Your docker run command syntax is wrong. Everything after the image name is used to override the command run in your container. So docker run myimage -d will try to run -d inside the container, while docker run -d myimage will run your container with the -d option to docker run (detached mode).
The Dockerfile you referenced is meant to be used as parent image for an easy dockerization of your application.
So to dockerize your nodejs application, you'd need to create a dockerfile using the docker image created by said dockerfile.
The ONBUILD instruction gets executed whenever a new image is built with this particular image as parent image (FROM instruction). More info
I've never used an image like this, but from the looks of it, it should be enough to reference the image with the FROM instruction and then provide the NODE_ENV via build args.
The dockerfile to add into your project:
FROM this_image:9.1
How to build your application image:
docker build -t IMAGE_NAME:TAG --build-arg NODE_ENV=production .

How to shrink size of Docker image with NodeJs

I created new Angular2 app by angular-cli and run it in Docker.
At first I init app on my local machine:
ng new project && cd project && "put my Dockerfile there" && docker build -t my-ui && docker run.
My Dockerfile
FROM node
RUN npm install -g angular-cli#v1.0.0-beta.24 && npm cache clean && rm -rf ~/.npm
RUN mkdir -p /opt/client-ui/src
WORKDIR /opt/client-ui
COPY package.json /opt/client-ui/
COPY angular-cli.json /opt/client-ui/
COPY tslint.json /opt/client-ui/
ADD src/ /opt/client-ui/src
RUN npm install
RUN ng build --prod --aot
EXPOSE 4200
ENV PATH="$PATH:/usr/local/bin/"
CMD ["npm", "start"]
Everything is OK, problem is size of image: 939MB!!! I tried to use FROM: ubuntu:16.04 and install NodeJs on it (it works), but still my image has ~450 MB. I know that node:alpine exists, but I am not able to install angular-cli in it.
How can I shrink image size? Is it necessary to run "npm install" and "ng build" in Dockerfile? I would expect to build app on localhost and copy it to image. I tried to copy dist dir and and package.json etc files, but it does not work (app start fail). Thanks.
You can certainly use my alpine-ng image if you like.
You can also check out the dockerfile, if you want to try and modify it in some way.
I regret to inform you that even based on alpine, it is still 610MB. An improvement to be sure, but there is no getting around the fact that the angular compiler is grossly huge.
For production, you do not need to distribute an image with Node.js, NPM dependencies, etc. You simply need an image that can be used to start a data volume container that provides the compiled sources, release source maps and other assets, effectively no more than what you would redistributed with a package via NPM, that you can attach to your webserver.
So, for your CI host, you can pick one of the node:alpine distributions and copy the sources and install the dependencies therein, then you can re-use the image for running containers that test the builds until you finally run a container that performs a production compilation, which you can name.
docker run --name=compile-${RELEASE} ci-${RELEASE} npm run production
After you have finished compiling the sources within a container, run a container that has the volumes from the compilation container attached and copy the sources to a volume on the container and push that to your Docker upstream:
docker run --name=release-${RELEASE} --volumes-from=compile-${RELEASE} -v /srv/public busybox cp -R /myapp/dist /srv/public
docker commit release-${RELEASE} release-${RELEASE} myapp:${RELEASE}
Try FROM mhart/alpine-node:base-6 maybe it will work.

Resources