My environment is: Ubuntu 18.04 Docker 19.03.11
I am working on a Flask app and am managing services with Docker. Here is my compose file:
version: '3.6'
x-build-args: &build_args
INSTALL_PYTHON_VERSION: 3.8
INSTALL_NODE_VERSION: 12
x-default-volumes: &default_volumes
volumes:
- ./:/app
- node-modules:/app/node_modules
- ./dev.db:/tmp/dev.db
services:
flask-dev:
build:
context: .
target: development
args:
<<: *build_args
user: abc
image: "testapp-development"
ports:
- "5000:5000"
- "2992:2992"
<<: *default_volumes
flask-prod:
build:
context: .
target: production
args:
<<: *build_args
image: "testapp-production"
ports:
- "5000:5000"
environment:
FLASK_ENV: production
FLASK_DEBUG: 0
LOG_LEVEL: info
GUNICORN_WORKERS: 4
<<: *default_volumes
manage:
build:
context: .
target: manage
environment:
FLASK_ENV: production
FLASK_DEBUG: 0
image: "testapp-manage"
stdin_open: true
tty: true
<<: *default_volumes
volumes:
node-modules:
static-build:
dev-db:
My Dockerfile:
# ==================================== BASE ====================================
ARG INSTALL_PYTHON_VERSION=${INSTALL_PYTHON_VERSION:-3.7}
FROM python:${INSTALL_PYTHON_VERSION}-slim-buster AS base
RUN apt-get update
RUN apt-get install -y \
curl \
gcc
ARG INSTALL_NODE_VERSION=${INSTALL_NODE_VERSION:-12}
RUN curl -sL https://deb.nodesource.com/setup_${INSTALL_NODE_VERSION}.x | bash -
RUN apt-get install -y \
nodejs \
&& apt-get -y autoclean
ARG user=sid
# Add the user and their group
RUN groupadd -r ${user} && useradd -m -r -l -g ${user} ${user}
# the /app directory contains things that npm needs
# user won't have permissions to this, so copy it
# into their home dir
WORKDIR /app
COPY --chown=${user}:${user} . /home/${user}/
USER ${user}
WORKDIR /home/${user}/app
ENV PATH="/home/${user}/.local/bin:${PATH}"
RUN npm install
# ================================= DEVELOPMENT ================================
FROM base AS development
RUN pip install --user -r requirements/dev.txt
EXPOSE 2992
EXPOSE 5000
CMD [ "npm", "start" ]
# ================================= PRODUCTION =================================
FROM base AS production
RUN pip install --user -r requirements/prod.txt
COPY supervisord.conf /etc/supervisor/supervisord.conf
COPY supervisord_programs /etc/supervisor/conf.d
EXPOSE 5000
ENTRYPOINT ["/bin/bash", "shell_scripts/supervisord_entrypoint.sh"]
CMD ["-c", "/etc/supervisor/supervisord.conf"]
# =================================== MANAGE ===================================
FROM base AS manage
RUN pip install --user -r requirements/dev.txt
ENTRYPOINT [ "flask" ]
Both the development and production target are failing
Here is the output I'm getting from running docker-compose build flask-dev
:
Building flask-dev
Step 1/20 : ARG INSTALL_PYTHON_VERSION=${INSTALL_PYTHON_VERSION:-3.7}
Step 2/20 : FROM python:${INSTALL_PYTHON_VERSION}-slim-buster AS base
---> 38cd21c9e1a8
Step 3/20 : RUN apt-get update
---> Using cache
---> 5d431961b77a
Step 4/20 : RUN apt-get install -y curl gcc
---> Using cache
---> caeafb0035dc
Step 5/20 : ARG INSTALL_NODE_VERSION=${INSTALL_NODE_VERSION:-12}
---> Using cache
---> 6e8a1eb59d3c
Step 6/20 : RUN curl -sL https://deb.nodesource.com/setup_${INSTALL_NODE_VERSION}.x | bash -
---> Using cache
---> 06fe96eb13e7
Step 7/20 : RUN apt-get install -y nodejs && apt-get -y autoclean
---> Using cache
---> 1e085132d325
Step 8/20 : ARG user=sid
---> Using cache
---> 3b3faf180389
Step 9/20 : RUN groupadd -r ${user} && useradd -m -r -l -g ${user} ${user}
---> Running in 9672d6f8b64d
Removing intermediate container 9672d6f8b64d
---> 02a5c2602513
Step 10/20 : WORKDIR /app
---> Running in bd48ac652908
Removing intermediate container bd48ac652908
---> 92c16bf347d4
Step 11/20 : COPY --chown=${user}:${user} . /home/${user}/
---> 2af997c5a255
Step 12/20 : USER ${user}
---> Running in 6409cf8784ee
Removing intermediate container 6409cf8784ee
---> 012d9cf92f31
Step 13/20 : WORKDIR /home/${user}/app
---> Running in a12b164c39dd
Removing intermediate container a12b164c39dd
---> db6fba37f948
Step 14/20 : ENV PATH="/home/${user}/.local/bin:${PATH}"
---> Running in eb13f4786b17
Removing intermediate container eb13f4786b17
---> a32249e3169b
Step 15/20 : RUN npm install
---> Running in 8aefdd56e8f2
npm WARN deprecated fsevents@1.2.13: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.1.2 (node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules/watchpack-chokidar2/node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
audited 712 packages in 2.873s
43 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Removing intermediate container 8aefdd56e8f2
---> 737faa9b974e
Step 16/20 : FROM base AS development
---> 737faa9b974e
Step 17/20 : RUN pip install --user -r requirements/dev.txt
---> Running in af5508643877
ERROR: Could not open requirements file: [Errno 2] No such file or directory: 'requirements/dev.txt'
ERROR: Service 'flask-dev' failed to build: The command '/bin/sh -c pip install --user -r requirements/dev.txt' returned a non-zero code: 1
I think my approach is wrong to this. I need to have the Flask app work out of the app volume that I'm using in the compose file.
What I think I'm misunderstanding is the multi-stage builds. Do I need to do extra steps in the development, production, and manage stages in order to be able to reach the /home/${user}/app directory? From what I understand ARGs defined in previous stages are not available in subsequent ones, but is all the processing done in a stage also not available in subsequent stages?
I have also tried using COPY --from=base in the second stage with the full path to where the app directory sits during the base build stage, but this isn't correct either.
The relevant parts of project directory are:
testapp/
docker-compose.yml
Dockerfile
testapp/
<web app code>
requirements/
dev.txt
prod.txt
You've copied your files into a different directory:
WORKDIR /app
COPY --chown=${user}:${user} . /home/${user}/
USER ${user}
WORKDIR /home/${user}/app
The requirements directory will be in /home/${user}/
while your relative run command will use the workdir to look in /home/${user}/app
. You likely want to copy into the app subdirectory:
COPY --chown=${user}:${user} . /home/${user}/app