Understanding Dockerfile syntax? - docker

I am learning Docker and looking at this Dockerfile example for React application
FROM node:alpine
WORKDIR /app
COPY package.json ./
COPY package-lock.json ./
COPY ./ ./
RUN npm i
CMD ["npm", "run", "start"]
To me it's saying
Grab image node:alpine from docker library
create WORKDIR called /app
copy the package.json file to the /app dir
copy the lock file also to /app dir
I don't understand what COPY ./ ./ is doing?
command npm install
then CMD npm run start
Am I interpreting this language correctly? Can anyone give me insight of what is actually going on?

Docker is an open-source containerization platform. Here we run our application in the container(which is managed by Docker Engine). Dockerfile contains all the commands. Also, you can say in Dockerfile that we write all the procedures to make a container runnable.
Coming back to your point...
Here COPY ./ ./ meaning is, COPY <source_path> <destination_path> and <source_path> is the path in your host machine and <destination_path> is path in your container machine
I will try to simplify the other contents in your Dockerfile...
FROM node:alpine : Pull image node:alpine from Docker Hub. Here node is the package name and alpine is the Linux distribution with very minimal and required packages.
WORKDIR /app: (Work Directory) In container you're setting up your WORKDIR as /app folder.
COPY package.json ./: COPY the package.json(host machine) file to ./(current directory) in your container
And other COPY will also work in the same way.
RUN npm i: RUN command npm i in container
CMD ["npm", "run", "start"]: CMD command will executed(npm run start) when Docker Container will start.
For more detail please see Dockerfile Documentation.

Related

Dockerfile copy from build failing for create-react-app

I have a react app I'm trying to dockerize for production. It was based off create-react-app. To run the app locally, I am in the app's root folder and I run npm start. This works. I built the app with npm run build. Then I try to create the docker image with docker build . -t app-name. This is failing for not being able to find the folder I'm trying to copy the built app from (I think).
Here's what's in my Dockerfile:
FROM node:13.12.0-alpine as build
WORKDIR /src
ENV PATH /node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm install --silent
COPY . ./
RUN npm run build
FROM nginx:alpine
COPY --from=build build /usr/share/nginx/html
EXPOSE 80
CMD ["npm", "start"]
I'm pretty sure I've got something wrong on the COPY --from line.
The app structure is like this, if it matters
-app-name (folder)
-src (folder)
-build (folder)
-dockerfile
-other stuff, but I think I listed what matters
The error I get is failed to compute cache key: "/build" not found: not found
I'm running my commands in windows powershell.
What do I need to change?
You were almost correct,
Just that the path where the build folder is generated is at /src/build and not at /build.
and hence the error you see,
and why the /src coming?
it's due to the WORKDIR /src.
and hence this should work: COPY --from=build /src/build /usr/share/nginx/html
besides, since you are using nginx server to serve the build static files,
you don't need to or you cant run npm start with CMD.
instead, just leave it, and you can access the application at port 80.
so the possible working Dockerfile would be:
FROM node:13.12.0-alpine as build
WORKDIR /src
ENV PATH /node_modules/.bin:$PATH
COPY package*.json ./
RUN npm install --silent
COPY . ./
RUN npm run build
FROM nginx:alpine
COPY --from=build /src/build /usr/share/nginx/html
EXPOSE 80
This is in accordance with the Dockerfile in the above question,
in some specific cases, advanced configuration might be required.

Solving the error of "docker build" not accesing package.json

I am trying to build an image for an express app and I have issues running the command. The error indicates that the package.json file is not accessible. Please look at the structure error below.
Sending build context to Docker daemon 2.048kB
Step 1/7 : FROM node:8-alpine
---> 2b8fcdc6230a
Step 2/7 : WORKDIR /usr/src/app
---> Using cache
---> d0f2d783ba5a
Step 3/7 : COPY package*.json ./
COPY failed: no source files were specified
Also, the docker file is shown below:
FROM node:8-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "npm", "start" ]
Then lastly the file structure is shown below:
I'd like any assistance possible. Thanks.
Use the command docker build . and it will run perfectly.
This could be due to the Node.JS version you are trying to use in the docker file, i'm not entirely sure if this is the case but I have used this docker file with my node.js express application and it seemed to work. Give it a shot.
FROM node:12
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Use COPY ./package*.json ./ like this in dockerfile.

Docker folder gets duplicated in container

Have this Dockerfile
Dockerfile
FROM python:3.8
ADD Pipfile.lock /app/Pipfile.lock
ADD Pipfile /app/Pipfile
WORKDIR /app
COPY . /app
RUN pip install pipenv
RUN pipenv install --system --deploy --ignore-pipfile
ENV FLASK_APP=app/http/api/endpoints.py
ENV FLASK_RUN_PORT=4433
ENV FLASK_ENV=development
ENTRYPOINT ["python"]
CMD ["-m", "flask", "run"]
Why in the Docker container my app lands in
/app/app/http/api
App gets duplicated
How to copy it to:
/app/http/api
How can I fix it?
Update 1:
My docker-compose and Dockerfile and ls output.
https://0bin.net/paste/ePRws72M#IV8H6iRJ+UMJFr8lB7CRQYKwsnGYflsmOlyvFxZA7zE
You got two problems here
copy . /app copies the whole working directory from the host machine into the /app directory in the image. If you just want the ./app subdirectory change that to copy ./app /app
Your docker-compose mounts the current working directory of the host machine into the container under the mount point /app . This hides the existing directory /app of the image. So you will either need to copy your app to a different directory or use a different mount point for your volume

Flask and React App in single Docker Container

Good day SO,
I know this is bad practice and that I am supposed to have one App per container, but is there a way for me to have two services running concurrently in the same container, and how would I go about writing the Dockerfile for it?
My current Dockerfile for the Flask (Backend) App:
FROM python:3.6.9-slim-buster
WORKDIR /app/flask_backend
ENV PYTHONPATH "${PYTHONPATH}:/app"
COPY ./flask_backend ./
COPY requirements.txt .
RUN pip install -r requirements.txt
CMD python3 app/webapp/app.py
My React (Frontend) Dockerfile:
FROM node:12.18.0-alpine as build
WORKDIR /app/react_frontend
ENV PATH /app/node_modules/.bin:$PATH
ENV NODE_OPTIONS="--max-old-space-size=8192"
COPY ./react_frontend/package.json ./
COPY ./react_frontend/package-lock.json ./
RUN npm ci
RUN npm install react-scripts#3.4.1 -g
RUN npm install serve -g
COPY ./react_frontend ./
CMD ["serve", "-s", "build", "-l", "3000"]
My attempt to launch both apps within the same Docker Container was to merge the two Dockerfiles, but the resulting container does not have the data from the first Dockerfile, and I am unsure how to proceed.
My merged Dockerfile:
FROM python:3.6.9-slim-buster
WORKDIR /app/flask_backend
ENV PYTHONPATH "${PYTHONPATH}:/app"
COPY ./flask_backend ./
COPY requirements.txt .
RUN pip install -r requirements.txt
CMD python3 app/webapp/app.py
FROM node:12.18.0-alpine as build
WORKDIR /app/react_frontend
ENV PATH /app/node_modules/.bin:$PATH
ENV NODE_OPTIONS="--max-old-space-size=8192"
COPY ./react_frontend/package.json ./
COPY ./react_frontend/package-lock.json ./
RUN npm ci
RUN npm install react-scripts#3.4.1 -g
RUN npm install serve -g
COPY ./react_frontend ./
CMD ["serve", "-s", "build", "-l", "3000"]
I am a beginner in using Docker, and hence I forsee that there will be several problems, such as communications between the two apps (Backend uses port 5000), using this method. Any guidiance will be greatly appreciated!
A React application doesn't usually have a server per se (development-only Docker setups aside). Instead, you run a tool like Webpack to compile it down to static files, which you can then serve to the browser, which then runs them.
On your host system you'd run something like
yarn build
which produces a dist directory; then you'd copy this into your Flask static directory.
If you do this entirely ahead-of-time, then you can run your application out of a Python virtual environment, which will be a much easier development and test setup, and the Dockerfile you show won't change.
If you want to build this entirely in Docker (for example to take advantage of a more Docker-native automated build system) a multi-stage build matches well here. You can use a first stage to build the front-end application, and then COPY that into the final application in the second stage. That looks roughly like:
FROM node:12.18.0-alpine as build
WORKDIR /app/react_frontend
COPY ./react_frontend/package.json ./
COPY ./react_frontend/package-lock.json ./
RUN npm ci
COPY ./react_frontend ./
RUN npm run build
FROM python:3.6.9-slim-buster
WORKDIR /app/flask_backend
ENV PYTHONPATH "${PYTHONPATH}:/app"
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY ./flask_backend ./
COPY --from=build /app/react_frontend/dist/ ./static/
CMD python3 app/webapp/app.py
This approach is not compatible with setups that overwrite Docker image contents using bind mounts. A non-Docker host Node and Python setup will be a much easier development environment, and for this particular setup isn't likely to be substantially different from the Docker setup.

Docker ExpressJS public folder volume

I want to create a volume for my "public" folder on Docker on Express App. Because when users upload pictures, I save them to "public/uploads", but when I make changes on code, and have to rebuild with docker-compose run --build, I lose all these images.
I tried to find a way to create a volume but I don't know how to link it.
My Dockerfile only consist of these:
FROM node:8.10.0-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
# RUN npm ci --only=production
COPY . .
CMD [ "npm", "start" ]
My goal is to serve uploaded images from "public/uploads", and don't get them removed upon docker-compose run --build.
According to the official documentation, you can use the --mount flag:
//Dockerfile
FROM node:8.10.0-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
# RUN npm ci --only=production
RUN --mount=target=/some_location_in_file_system,type=bind,source=public/uploads
COPY . .
CMD [ "npm", "start" ]

Resources