Django static files not serving when running inside Docker container - python

I have a django application thats is rendering the static files when run outside docker container. I added a Dockerfile so that I can run it in a container. However, the static files are not getting served when running in the container
The sample app that I have used can be found here
I have added the following Dockerfile at the root level
FROM python:3.8
#add project files to the usr/src/app folder
ADD . /usr/src/app
#set directoty where CMD will execute
WORKDIR /usr/src/app/wisdompets
COPY requirements.txt ./
# Get pip to download and install requirements:
RUN pip install --no-cache-dir -r requirements.txt
# Expose ports
EXPOSE 8000
# default command to execute
CMD exec gunicorn wisdompets.wsgi:application --bind 0.0.0.0:8000 --workers 3
And the requirements.txt file at root level as below
django==3.0.3
gunicorn==20.0.4
The static files settings in my settings.py is as follows
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
Please let me know if there's something wrong with my configuration

You are missing collectstatic command which will package static files alongside the app.
Check this link for reference.

Revisa keeps you configured.
STATIC_ROOT
You should have no problems when you run the command.
python manage.py \
collectstatic \
--verbosity 0 \
--noinput \
--clear
If it's fine but still doesn't render the statics.
Check the gunicorn documentation.
I recommend you to use uwsgi is much more elegant.
https://uwsgi-docs.readthedocs.io/en/latest/

Related

Could not locate a Flask application when creating a Docker Image

I hope someone can help me with this. The following error code comes up when I try and run docker run todolist-docker.
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
Error: Could not locate a Flask application. You did not provide the "FLASK_APP" environment variable, and a "wsgi.py" or "app.py" module was not found in the current directory.
My folder directory is here:
Folder name: todoflaskappfinal
__pycache__
static
templates
venv
App.py
Dockerfile
requirements.txt
todo.db
ToDoList.db
within the todoflaskappfinal folder, I have a Dockerfile file:
# syntax=docker/dockerfile:1
FROM python:3.7.8
WORKDIR /tododocker
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]
And within App.py, I've set up everything (I assume) correctly, obviously with more code between this.
#Website Configuration
app = Flask(__name__)
if __name__ == "__main__":
app.run(debug=True, port=5000, host='0.0.0.0')
I've set FLASK_APP as App.py, made the virtual environment with venv, etc. When I type in flask run in the terminal it loads the website up correctly and displays it on 127.0.0.01. However, when I try and use the docker build --tag todolist-docker command and then docker run todolist-docker, the error message appears above. Can anyone see what I'm doing wrong?
Is FLASK_APP defined in the docker container? There's no ENV statement in the Dockerfile, and you didn't mention using docker's -e or --env command option. Your container won't inherit your environment variables from the hosting environment.
# syntax=docker/dockerfile:1
FROM python:3.7.8
WORKDIR /tododocker
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
# Add this:
ENV FLASK_APP=App.py
CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]

Why is this not in the Dockerfile?

I've been messing with Docker and Django lately and rather than clutter up my system, I decided to make a dev container for Django.
I've got it working but I want to know the "why" of this situation.
I followed this tutorial on the Docker website and finally got everything working. I don't get why we do
docker-compose run web django-admin startproject composeexample and not put the django-admin startproject composeexample inside the Dockerfile or the compose file?
EDIT: Here's what I have tried with my limited Docker knowledge:
On separate Dockerfiles I've tried...
CMD django-admin startproject django-tests and CMD ['django-admin startproject django-tests']
And I tried...
command: django-admin startproject django-tests
I've tried to do both but it wont work, it builds the image but without a django project being created. I get a manage.py not found error.
I feel like the project should be inside the image and not have to be run at the end of the docker-compose run command.
So why do we do this and why doesn't putting it inside the Dockerfile work?
I don't get why we do docker-compose run web django-admin startproject composeexample and not put the django-admin startproject composeexample inside the Dockerfile or the compose file?
Because this command is a one-time initialization command that creates a Django project template in your current directory on the host. It doesn't make sense to bake this into a Dockerfile; you will only ever run this once when first creating your project. That's why you're using docker-compose run here, which is for short-lived ad-hoc commands.
Compare the directory before docker-compose run web django-admin startproject composeexample .:
$ ls
docker-compose.yml Dockerfile requirements.txt
And after:
$ ls
composeexample docker-compose.yml Dockerfile manage.py requirements.txt
Running that command created the composeexample directory tree and manage.py files for us.
This works because of the volume configuration in the
docker-compose.yml file:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
That mounts the current directory (.) as /code inside the
container. Meanwhile, the Dockerfile makes /code the current
working directory:
WORKDIR /code
So when we run the startproject command, files are created inside
/code inside the container which corresponds to our local directory
on the host.
I don't get why we do docker-compose run web django-admin startproject composeexample and not put the django-admin startproject composeexample inside the Dockerfile or the compose file?
Because you don't want to create a new project inside a container. We want to build it locally, add it to container and have the container ready to go with all necessary files wherever this container is deployed.
manage.py not found
This means that you either have not copied the project files into your container or you run you command inside the wrong directory. You can do WORKDIR in the docker-compose or you can get inside your container (it must be running) with
docker exec -it <mycontainer> bash
and see which folder your project is in (if it's there)

Django Whitenoise with compressed staticfiles

I'm not able to get my django project to run with whitenoise and compressed staticfiles (including libsass). In links below, I read that it's only possible by offline compression of needed staticfiles. But when I started up the docker container, running compress command
docker-compose -f production.yml run --rm django python manage.py compress
gives me error:
ValueError: Missing staticfiles manifest entry for 'sass/app.scss'
While trying to request the site gives me following error (as expected?):
compressor.exceptions.OfflineGenerationError: You have offline compression enabled but key "..." is missing from offline manifest. You may need to run "python manage.py compress"
Settings are as follows (build with cookiecutter-django, see link for complete code base below):
STATIC_ROOT = str(ROOT_DIR("staticfiles"))
STATIC_URL = "/static/"
STATICFILES_DIRS = [str(APPS_DIR.path("static"))]
STATICFILES_FINDERS = [
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
]
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
STATICFILES_FINDERS += ["compressor.finders.CompressorFinder"]
COMPRESS_PRECOMPILERS = [("text/x-scss", "django_libsass.SassCompiler")]
COMPRESS_CACHEABLE_PRECOMPILERS = (("text/x-scss", "django_libsass.SassCompiler"),)
COMPRESS_ENABLED = env.bool("COMPRESS_ENABLED", default=True)
COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage"
COMPRESS_URL = STATIC_URL
So after searching the internet for 1 day; I'm stuck... Thx for any help or suggestion!
Code base: https://github.com/rl-institut/E_Metrobus/tree/compress
which is build with cookiecutter-django-foundation
including the following changes to config/setttings/production.py:
COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage" # Instead of pre-set "storages.backends.s3boto3.S3Boto3Storage"
COMPRESS_ROOT = STATIC_ROOT # Just in case
COMPRESS_OFFLINE = True # Needed to run compress offline
Possible related links:
Whitenoise and django-compressor cause 404 for compressed files
Possible to use WhiteNoise with Django-Compressor?
Django staticfiles not found on Heroku (with whitenoise)
https://github.com/django-compressor/django-compressor/issues/486
EDIT
Solved it using Justins answer (see below, with additonal changes).
My mistake was trying to compress files with already running container, giving me the error above. After changing Dockerfile with following lines (Notice the duplicate collectstatic cmd!):
python /app/manage.py collectstatic --noinput
python /app/manage.py compress --force
python /app/manage.py collectstatic --noinput
/usr/local/bin/gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app
and rebuilding image everything worked like a charm :)
Additionally, diverging from settings above, I had to set COMPRESS_ENABLED=True in my settings/env file.
I just had the same problem.
Add this to project/compose/production/django/start
python /app/manage.py compress --force
i.e.
python /app/manage.py collectstatic --noinput
python /app/manage.py compress --force
/usr/local/bin/gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app
this is weird but it work very well.
collect and compress static files by whitenoise
python manage.py collectstatic --clear
set COMPRESS_STORAGE = 'compressor.storage.BrotliCompressorFileStorage'
to make .br files in CACHE directory
python manage.py compress --force
set COMPRESS_STORAGE = 'compressor.storage.GzipCompressorFileStorage'
to make .gzfiles in CACHE directory
python manage.py compress --force
to add new compressed files to whitenoise: manifest.json, manifest.json.gz,
manifest.json.br
--no-post-process option is to tell whitenoise not to compress static files again.
python manage.py collectstatic --no-post-process
make sure to run the commands in order.
to test if whitenoise is working
python manage.py runserver --nostatic

Volume to share files from docker container to host in elastic beanstalk single container

I'm trying to share the static files from my container to the host so that nginx can serve them. This is on AWS elastic beanstalk using the Docker single container platform.
I have verified that the static files have been generated in the container, however the files are not found in the host directory.
The project is otherwise working fine, deployed with eb deploy.
Can someone tell me where did I go wrong? Thanks!
Dockerrun.aws.json:
{
"AWSEBDockerrunVersion": "1",
"Volumes": [
{
"HostDirectory": "/var/www/static",
"ContainerDirectory": "/code/my_app/static"
}
]
}
Dockerfile:
FROM python:3.6
ENV PYTHONUNBUFFERED 1
ARG requirements=requirements/production.txt
ENV DJANGO_SETTINGS_MODULE=my_app.settings.production
RUN mkdir /code
WORKDIR /code
COPY requirements/ /code/requirements/
RUN pip install --upgrade pip
RUN pip install -r $requirements
STOPSIGNAL SIGINT
ADD . /code/
EXPOSE 8000
COPY ./entrypoint_prod.sh /
ENTRYPOINT ["/entrypoint_prod.sh"]
entrypoint_prod.sh
python manage.py collectstatic --no-input
gunicorn my_app.wsgi:application --bind 0.0.0.0:8000
python manage.py process_tasks

Collectstatic configuration error when deploying Django app with dokku

When deploying a Django app using dokku I am getting a following error
Collectstatic configuration error. To debug, run:
$ heroku run python ./manage.py collectstatic --noinput
I found no way to run heroku run python ./manage.py collectstatic --noinput for a dokku container, but when I am trying dokku run my app python ./manage.py collectstatic --noinput, the static files are successfully copied to the STATIC_ROOT folder and no error message given.
I could solve the problem by placing collectstatic command into Procfile:
web: python manage.py collectstatic --noinput ; gunicorn myapp.wsgi
Still, I would love to know what was causing the problem and how can it be debugged. Any ideas?
You should have four settings in your settings.py file called MEDIA_ROOT, MEDIA_URL, STATIC_ROOT and STATIC_URL.
I set mine like so:
MEDIA_ROOT = 'media'
STATIC_ROOT = 'static'
MEDIA_URL = '/media'
STATIC_URL = '/static'
Inside the docker container that gets created, you will find your application under /app which makes the media path /app/media/ and the static path /app/static/.
Unfortunately if you don't have a media and static folder committed in git, it won't get created under /app automatically.
Since git doesn't allow you to commit an empty folder (it only commits files), I do the following in my projects:
mkdir media static
touch media/.dir
touch static/.dir
git add media/.dir static/.dir
git commit -m 'Make media and static directories'
The 'touch' command creates an empty file, then you 'git add' the two newly-created files and check them in.
Now when you push, the directories will be there to contain the media and static files. Just keep in mind that every time you 'git push', a new container is created, and the old one is destroyed. While this isn't a problem for your static files, your media will be lost unless you store it somewhere else.

Categories