Flask and React App in single Docker Container - docker

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.

Related

SvelteKit - npm run build - how to run the application for production? (Dockerized, if possible)

I built a Svelte app with Sveltekit. After running npm run build, I get a .svelte-kit folder with different folders. There is an output folder with subfolders called client and server, which might be promising. I also try to Dockerize my app.
I am able to run npm run preview, but this seems not to be suited for production. What is the way to actually run my svelte application? I have seen in other repos, where the app is run with the following command: CMD ["node", "build/index.js"]
I currently have this:
FROM node:18-alpine AS builder
WORKDIR /app
COPY ./frontend/package*.json ./
RUN npm install
COPY ./frontend .
RUN npm run build
FROM node:18-alpine
RUN mkdir /app
COPY --from=builder /app/package.json .
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.svelte-kit/output ./output
EXPOSE 5577
# See if increase libuv thread pool size makes performance better
# The default value 4
# http://docs.libuv.org/en/v1.x/threadpool.html
ENV UV_THREADPOOL_SIZE=32
CMD ["node", "/output/server/index.js"]
The command itself works, but running the index.js file just runs through with no error.
How do I actually run my app after creating the production build?
Thanks in advance

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.

Run Multiple Commands In Dockerfile

I want to run the booksServer first, then the customersServer, then fire main.js
But before firing off main.js I want to make sure that customersServer and booksServer are running first.
How do I do this properly?
Here's my dockerfile now
FROM node:12.14.0
WORKDIR /usr/src/app
COPY package*.json ./
COPY . /usr/src/app
RUN npm install
RUN npm install nodemon -g
EXPOSE 4555
CMD nodemon /books/booksServer.js && nodemon /customers/customersServer.js && node /main/main.js
I know usually you want to separate containers for multiple processes, but I was having gRPC issues when doing this... So I want to try it as a single dockerfile for now.
Assuming booksServer.js and customersServer.js are offering ports for communication you could use this script. The script is commonly used to wait for another service to be ready to used.

Does automatically updating my package.json at commit time disable docker build to reuse cache?

I've just started to get deep inside dockerfile syntax.
Here is the one I use currently:
FROM node:12-alpine as install
WORKDIR /Backend-graphql
COPY ./src ./src
COPY ./index.js ./index.js
COPY ./schema.graphql ./schema.graphql
COPY ./package.json ./
COPY ./package-lock.json ./package-lock.json
RUN npm install
FROM node:12-alpine as prismawork
WORKDIR /PrismaWork
COPY --from=install /Backend-graphql .
COPY ./datamodel.prisma ./datamodel.prisma
COPY ./prisma.yml ./prisma.yml
RUN npx prisma deploy
RUN npx prisma generate
FROM node:12-alpine
#curl needed for healthcheck
RUN apk --update --no-cache add curl
WORKDIR /app
COPY --from=prismawork /PrismaWork .
ENTRYPOINT ["npm", "start"]
EXPOSE 4000
From personnals tests and documentations founds online, i've respected the following advice :
Use multi-stage builds
But I notice something, docker do not reuse cache after the first COPY layer different in current and followings build stages. And I think its a problem, because I use an automatic bump version git hook based on commit message semantic versionning syntax who modifies my package.json. So, at each commit docker build re-RUN npm install and subsequents layers.
First of all, have I understood docker cache layering system ?
Secondly, should I use an other file for automatic bumping version and COPY it at the very end of my Dockerfile ?
First of all, have I understood docker cache layering system?
Yes, you should.
If any change happens in any step, like changes in package.json, the docker will rebuild the rest of the steps.
No need to copy from the same image multiple times. We are also doing npm install after performing unrelated steps to catching other steps.
FROM node:12-alpine
#curl needed for healthcheck
RUN apk --update --no-cache add curl
WORKDIR /app
COPY ./src ./src
COPY ./index.js ./index.js
COPY ./schema.graphql ./schema.graphql
COPY ./datamodel.prisma ./datamodel.prisma
COPY ./prisma.yml ./prisma.yml
COPY ./package.json ./
COPY ./package-lock.json ./package-lock.json
RUN npm install
RUN npx prisma deploy
RUN npx prisma generate
ENTRYPOINT ["npm", "start"]
EXPOSE 4000
Multiple staging useful when you need to build between multiple images like this example:
FROM node:12-alpine
RUN npm install -g gzipper
WORKDIR /build
ADD . .
RUN npm install
ARG CONFIGURATION
RUN npm run build:${CONFIGURATION}
RUN gzipper --gzip-level=6 ./dist
FROM nginx:latest
WORKDIR /usr/share/nginx/html
COPY --from=0 /build/dist .
COPY nginx/default.conf /etc/nginx/conf.d/default.conf

Dockerize two things and use in one directory

I have an Angular - Flask app that I'm trying to dockerize with the following Dockerfile:
FROM node:latest as node
COPY . /APP
COPY package.json /APP/package.json
WORKDIR /APP
RUN npm install
RUN npm install -g #angular/cli#7.3.9
CMD ng build --base-href /static/
FROM python:3.6
WORKDIR /root/
COPY --from=0 /APP/ .
RUN pip install -r requirements.txt
EXPOSE 5000
ENTRYPOINT ["python"]
CMD ["app.py"]
On building the image and running the image, console gives no errors. However, it seems to be stuck. What could be the issue here?
Is it because they are both in different directories?
Since I'm dockerizing Flask as well as Angular, how can I put both in same directory (right now one is in /APP and the other in /root)
OR should I put the two in separate containers and use a docker-compose.yml file?
In that case, how do I write the file? Actually my Flask calls my Angular and both run on same port. So I'm not sure if running in two different containers is a good idea.
I am also providing the commands that I use to build and run the image for reference:
docker image build -t prj .
docker container run --publish 5000:5000 --name prj prj
In the Angular build first stage of the Dockerfile, use RUN instead of CMD.
CMD is for running a command after the final image is built.

Resources