Make static files from django's collecstatic part of Docker image - django

I want to include static files generated from python manage.py collectstatic in the Docker image.
For this, I included the following line in my Dockerfile
CMD python manage.py collectstatic --no-input
But since it runs the command in an intermediate container, the generated static files aren't present STATIC_ROOT directory. The following lines I can see on the logs of build.
Step 13/14 : CMD python manage.py collectstatic --no-input
---> Running in 8ea5efada461
Removing intermediate container 8ea5efada461
---> 67aef71cc7b6
I'd like to include the generated static files in the image. What shall I do to achieve this?
Update ( solution )
I was using CMD but instead, I should use RUN command for this task as the docs say
The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.

You need to copy the output of collectstatic into your final container.
For example, my dockerfile contains the same concept (this isn't the complete dockerfile, just the relevant pieces)
# Pull base image
FROM python:3.7.7-slim-buster AS python-base
COPY requirements.txt /requirements.txt
WORKDIR /project
RUN apt-get update && \
apt-get -y upgrade && \
pip install --upgrade pip && \
pip install -r /requirements.txt
FROM node:8 AS frontend-deps-npm
WORKDIR /
COPY ./package.json /package.json
RUN npm install
COPY . /app
WORKDIR /app
RUN /node_modules/gulp/bin/gulp.js
FROM python-base AS frontend-deps
COPY --from=frontend-deps-npm /app /app
WORKDIR /app
RUN python manage.py collectstatic -v 2 --noinput
FROM python-base AS app
COPY . /app
COPY --from=frontend-deps /app/static-collection /app/static-collection

Related

Why is the download attribute no longer working after running my Django App in a docker image?

After running a docker image of my django app, I notice that downloading files is no longer available. The only thing I get is a copy of the website page I am currently on and not the requested file.
Locally, it is working fine.
Here is how my code is organized :
In main/views.py :
path_to_report = f"media/Reports/{request.user.username}/{request.user.username}{now.hour}{now.minute}{now.second}.txt"
return render(request, "main/result.html", {"dic_files": dic_files, "nbr":len(files), "dic_small":dic_small, "dic_projects":dic_projects, "path_to_report":f"/app/{path_to_report}"})
In main/result.html
<a href=/{{path_to_report}} download>
<button class="btn btn-success" name="rapport" value="rapport"> Télécharger votre rapport</button>
</a>
Here is my dockerfile :
# Use the official lightweight Python image.
# https://hub.docker.com/_/python
FROM python:3.8
# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True
EXPOSE 8000
## api-transport-https installation
RUN apt-get install apt-transport-https ca-certificates gnupg
# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./
# Install production dependencies.
RUN pip3 install --upgrade pip setuptools wheel
RUN pip3 install -r requirements.txt
RUN python manage.py makemigrations
RUN python manage.py migrate
RUN python manage.py collectstatic --no-input
ENTRYPOINT ["gunicorn", "myteam.wsgi:application", "--bind=0.0.0.0:8000", "--workers=4", "--timeout=300", "--log-level=debug"]
In your main/views.py, try replacing:
"path_to_report":f"/app/{path_to_report}"
with :
"path_to_report":path_to_report

/entrypoint.sh: line 8: syntax error: unexpected end of file

Docker project was created on Linux machine, I'm running windows and I can't get docker-compose up to work. I've read through Stackoverflow's answers and so far I've tried the following (none have worked):
Using Visual Studio Code I saved as "LF" instead of CRLF
Deleted the file entirely, created a new one using Visual Studio Code, typed the words
Cut the entire file, pasted it in Notepad so that formatting gets cleared, copied and pasted back
Added various forms of #!/bin/bash to the start of the entrypoint.sh
Changed Docker File to use COPY instead of ADD
At this point I'm not sure what else to try. Any ideas?
Edit
entrypoint.sh
if [ "$1" == 'celery' ]; then
celery -A vicmun worker -l info --uid=celery --gid=celery
else
./../wait_for_it.sh db:5433 --timeout=10
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
fi
Dockerfile
FROM python:3.9
ENV PYTHONUNBUFFERED 1
ARG APP_ENV=${APP_ENV}
RUN mkdir /src
RUN mkdir /static
WORKDIR /src
ADD ./src /src
ADD entrypoint-${APP_ENV}.sh /entrypoint.sh
ADD wait_for_it.sh /wait_for_it.sh
RUN addgroup --system celery && adduser --system --ingroup celery celery
RUN ["chmod", "+x", "/wait_for_it.sh"]
RUN apt-get -y update
RUN apt-get -y install ffmpeg
RUN pip install -r requirements.txt
ENTRYPOINT ["bash", "/entrypoint.sh"]
I don't know your config, but I could resolve that problem by adding in the CMD.
In my case, I could execute a script with docker as follows:
Dockerfile
FROM python:3.10-alpine3.15
ENV PYTHONUNBUFFERED=1
WORKDIR /app
RUN apk update \
&& apk add --no-cache gcc musl-dev postgresql-dev python3-dev libffi-dev \
&& pip install --upgrade pip
COPY requirements.txt .
RUN python -m pip install -r requirements.txt
COPY . .
CMD [ "sh", "entrypoint.sh" ]
entrypoint.sh
#!/bin/sh
python manage.py makemigrations
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
Well, I feel the cringe for this. Turns out the solution was something I had already done, but it didn't go through until I rebuilt with --no-cache option.
Solution was to:
Using Visual Studio Code I saved as "LF" instead of CRLF
and run docker-compose build --no-cache

gunicorn: command not found django

Using Docker to install gunicorn, I am unable to to use the gunicorn command.
To start Django, I have this line in my docker-compose.yaml:
command: bash -c "python manage.py makemigrations && python manage.py migrate && gunicorn myproject.wsgi -b 0.0.0.0:8000"
This results in bash: gunicorn: command not found
When I build the Docker images it says gunicorn has been successfully installed.
My Dockerfile looks like:
FROM python:3.5
ENV PYTHONUNBUFFERED 1
RUN mkdir /config
ADD requirements.txt /config/
RUN pip install -r /config/requirements.txt
RUN mkdir /src;
WORKDIR /src
I've been using this http://ruddra.com/2016/08/14/docker-django-nginx-postgres/ as a guide.
If you are finding that gunicorn doesn't exist it could be because
docker image may use a cached layer of the requirements.txt which doesn't have gunicorn in it as a dependency.
Therefore it will result in not installing gunicorn meanwhile specifying pip install gunicorn in a seperate RUN command will work.
Solution:
Build docker image without caching when edits have been made to requirements.txt
docker build --no-cache .

Docker error with pipenv on django app: Warning: --system is intended to be used for pre-existing Pipfile

When I was trying to dockerize my django app, I followed a tutorial telling me to structure my Dockerfile like this
FROM python:3.6
ENV PYTHONUNBUFFERED 1
COPY . /code/
WORKDIR /code/
RUN pip install pipenv
RUN pipenv install --system
EXPOSE 8000
After I saved that and run docker build .
the system threw me this error
Warning: --system is intended to be used for pre-existing Pipfile
installation,not installation of specific packages. Aborting.
I think it is complaining about the --system suffix above but the tutorial says it's crucial to have it so that my packages are applied in the entire docker container. I'm new to docker and even pipenv because I took over a previous person's code and isn't sure where their pipfile is or even if they have a pipfile. If you have any insights on how to fix this error thank you in advance.
pipenv --rm
This helped me! I was starting the "Django for beginners" and at the very beginning, got this error (accidently deleted Pipfile & Pipfile.lock)
Your warning is saying you that there is no Pipfile in your project dir.
--system is intended to be used for pre-existing Pipfile.
So before running
docker build .
run
pipenv install
in your project folder
Above solution didn't work for me.
After installing in the virtual env I also had to explicitly include Pipfile and Pipfile.lock into my dockerfile:
COPY Pipfile* .
# Install dependencies
RUN pip install pipenv && pipenv install --system
Then rebuild with docker compose:
docker-compose build
You can find more info in this thread
It has Error in pipenv
It is 👇 ERROR:: --system is intended to be used for pre-existing Pipfile installation, not installation of specific packages. Aborting.
try it
pipenv check or python3 -m pipenv check
Be careful when using Docker bind mounts!
Summary: In my case, I was using bind mounts in my dev environment, and mounting a docker bind mount on a non-empty directory would overwrite the contents of the container's directory, removing the Pipfile and Pipfile.lock, which showed the error mentioned when running the container.
Explanation
Directory structure on the host
> ls project/
docker-compose.yml Dockerfile Pipfile Pipfile.lock app/
Dockerfile
My Dockerfile would copy the contents of the project and then install the dependencies with pipenv, like this:
FROM python:3.8
# ...
COPY Pipfile Pipfile.lock /app/
RUN pipenv install --deploy --ignore-pipfile
COPY ./app /app/
CMD ["pipenv", "run", "uvicorn", "etc..", "--reload"]
Pipfile, Pipfile.lock and the code of ./app would all be in the same /app directory inside the container.
docker-compose.yml
I wanted uvicorn to hot-reload, so I mounted the code in /app inside the container's /app directory.
service:
app:
#...
volumes:
- type: bind
source: ./app
target: /app
This meant that when I changed the code in /app, the code in the container's /app directory would also change.
Effects
The side effect of this bind mount is that the content mounted on /app "obscured" the content previously copied in there.
Container's content with the bind mount:
> ls app/
code1.py code2.py
Container's content without the bind mount:
> ls app/
Pipfile Pipfile.lock code1.py code2.py
Solution
Either make sure that you include the Pipfile and Pipfile.lock as well when mounting the bind mount, or make sure that you COPY these 2 files to a directory that won't get overwritten by a bind mount.

Django running in Docker container: makemigrations and migrate do not see app's model on launch

I have Django running in a Docker container. The CMD of my Docker file simply runs a script, launch.sh, which inter alia has the following commands:
python manage.py makemigrations --no-input --verbosity 1
python manage.py migrate --no-input --verbosity 1
So, these commands make migrations on my Django project, and then perform the migrations (if any), whenever my container launches. This works as intended for the specifically project-level migrations.
However, inevitably, only the project-level migrations are made — that is, the app-level migrations are never made and so are never performed. But if I log into the container (with docker exec -it ... bash) and execute the same migration commands manually, the app-level migrations are made and performed.
Googling and numerous variations to my code haven't turned up any explanations for this behavior or any fix, so I'm stumped.
Any ideas?
P.S. Here is my project and app structure:
/django/
project/
app/
static/
manage.py
Also, I tried executing the same set of commands twice in succession in my script, and also running the same set of commands in succession but with my app specified as the target option, but these attempts still produced the same results: only the project migrations are made, not the app migrations.
As asked, here's my Dockerfile:
FROM python:3-slim
ENV PYTHONUNBUFFERED 1
ADD django-requirements.pip .
RUN pip install --upgrade pip && \
pip install --no-cache-dir -r django-requirements.pip
WORKDIR /
ADD launch.sh .
CMD ./launch.sh
My Django project is mounted at launch at /django, and my launch script CDs to /django before running the migration commands.
Check your Django app Dokerfile for WORKDIR
# In my case it is /app
WORKDIR /app
and change your launch.sh file
# manage.py will be inside working dir
python /app/manage.py migrate --noinput
UPDATE
It depends on where you copied launch.sh file inside the
container.
If you copied all files of Django app inside /app dir
COPY . /app
and copy your launch.sh file outside it like
COPY ./<path to launch file>/launch.sh /launch.sh
then inside launch.sh you have to use manage.py as
# should prepend `/app/`
python /app/manage.py migrate --noinput
But if you copied launch.sh inside /app/ as.
COPY ./<path to launch file>/launch.sh /app/launch.sh
Then you can use migrate command as the traditional way
python manage.py migrate --noinput
Now When you run the command using docker exec -it container-id, Then it runs
inside working DIR and locates manage.py file.
I had exactly the same problem.
I think there must be a migrations/__init__.py in your Django app dir.
Be sure that you copied it to your container.
My solution was to change a line in .dockerignore:
app/migrations/* to app/migrations/0*.