skip to Main Content

I’m new into Docker. I have a problem with uploading file in Flask app that is contained in Docker and accessing it.

Let’s say that I have a project in this structure:

/home
| /myProjects
  | /myDockers
  | | /myApp
  | | | /controller
  | | | ...
  | | | wsgi.py
  | | | .gitlab-ci.yml
  | | | DockerFile
  | | | gunicorn.sh
  | /uploads

My Flask app is in /MyApp, while I want to upload file into /uploads. The app was deployed on Docker with these configurations:

.gitlab-ci.yml:

stages:
  - build
  - deploy

build-image:
  stage: build
  only:
    refs:
      - dev
  script:
    - cd /home/myProjects/myDocker/myApp/
    - git checkout dev
    - git pull origin dev
    - docker container rm -f myApp
    - docker image rm -f myApp
    - docker build -t myApp -f 20021_DockerfileLmsGeneralRepositoryService .

deploy-container:
  stage: deploy
  only:
    refs:
      - dev
  script:
    - docker run -d --network host -e DATABASE_URL=$DATABASE_URL -e REDIS_HOST=$REDIS_HOST --name myApp myApp

DockerFile:

FROM python:3.8.7-slim-buster AS compile-image
RUN apt-get update && apt-get install -y --no-install-recommends build-essential gcc libpq-dev && apt-get install -y apt-utils

COPY ./requirements.txt .
RUN pip install --upgrade --user -r requirements.txt
RUN pip install injector


COPY . /code

FROM python:3.8.7-slim-buster AS build-image
COPY --from=compile-image /code/ /code
COPY --from=compile-image /root/.local /root/.local

# Make sure scripts in .local are usable:
ENV PATH=/root/.local/bin:$PATH
WORKDIR /code

RUN chmod a+x gunicorn.sh
ENTRYPOINT ["sh","./gunicorn.sh"]

gunicorn.sh:

#!/bin/sh
gunicorn wsgi:application -w 2 --threads 2 --preload -b 0.0.0.0:20021

I already create an API in my Flask app to upload file and succeed in local (Windows) PC, but then when I deploy it into the development server, the structure of folder is different from what I expected. When I checked the project structure using script, it returned:

"/code/controller"

Which is different from the structure of the project in the server, so I ask my senior and he said I should learn about Volume in Docker since the project is contained inside Docker container, but I never used Docker in the first place.

I also already tried to change the script in .gitlab-ci.yml into this (I tried this from this question) and yeah it doesn’t work:

- docker run -d --network host -e DATABASE_URL=$DATABASE_URL -e REDIS_HOST=$REDIS_HOST --name myApp -v /home/myProjects/:/root/.local/code myApp

2

Answers


  1. you are using cd /home/myProjects/myDocker/myApp/ in CI file and COPY . /code in docker build file.

    that means "whatever you see in host’s /home/myProjects/myDocker/myApp/ folder, copy them all into /code folder of the container". thus your ...myApp/* becomes /code/*

    but your pain is not just that. from the app’ perspective, you are writing uploaded files into ../../uploads but you don’t have such a folder in your container. also note that you have 2 parent levels in your host and your app is looking for such a path and won’t find inside the container anyways because your project is only 1 level deep from the root level.

    in this latter situation, change your code to read uploads folder path from the environment (os.environ?), set default to be ../../uploads for your development, create a folder inside your container such as /uploads, add its path in your docker file with ENV then map host and container upload folder paths with volume command, possibly -v home/myProjects/uploads:/uploads


    edit:

    I have written a simple app doing the above last paragraph. please visit this address: https://github.com/yilmazdurmaz/basicbindmount

    Login or Signup to reply.
  2. After our talk, I could see another and easier solution. parts of my other answer are still applying.


    from your working folder structure, your app seems to try writing to ../../uploads folder, 2 levels up in directory structure. thus we can create a folder structure in the container to suit this.

    in Dockerfile make these changes:

    • edit COPY --from=compile-image /code/ /code to COPY --from=compile-image /code/ /code/app
    • edit WORKDIR /code to WORKDIR /code/app
    • add RUN mkdir /uploads anywhere after FROM .. AS build-image and but before ENTRYPOINT

    we copy the app 2 level deep in the container and adding uploads folder into root.

    now run change your run command into this:

    docker run -d --network host -e DATABASE_URL=$DATABASE_URL -e REDIS_HOST=$REDIS_HOST --name myApp -v /home/myProjects/uploads:/uploads myApp
    

    we bind-mount an uploads folder in the host into the uploads folder in the container. you can have the bind as -v path_to_your_uploads_folder_in_host:/uploads

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search