I am building a Django app with Docker. I run the command collectstatic in my entrypoint when database is ready. When I check my container, the /static/ folder is empty. Thus, Nginx cannot load the static files.
# settings.py
STATIC_URL = '/static/'
STATIC_ROOT = '/static/'
Here is my docker-compose file
version: "3.9"
services:
db:
image: postgis/postgis:14-3.3
container_name: db
volumes:
- ./data/db:/var/lib/postgresql/data
env_file:
- prod.env
backend:
container_name: backend
build:
dockerfile: ./django/Dockerfile
command: gunicorn api.wsgi:application --bind 0.0.0.0:8000
volumes:
- static:/usr/src/app/static
ports:
- "8000:8000"
env_file:
- prod.env
depends_on:
- db
nginx:
container_name: nginx
build:
dockerfile: ./nginx/Dockerfile
volumes:
- static:/usr/src/app/static
ports:
- "80:80"
depends_on:
- backend
restart: always
redis:
container_name: redis
restart: unless-stopped
image: redis:alpine
expose:
- 6379
worker:
container_name: worker
build:
dockerfile: ./django/Dockerfile
command: celery -A api worker -l INFO
volumes:
- static:/usr/src/app/static
env_file:
- prod.env
depends_on:
- db
- backend
- redis
volumes:
static:
My Nginx configuration:
upstream api {
server backend:8000;
}
server {
listen 80;
location / {
proxy_pass http://api;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /usr/src/app/static/;
}
}
backend Dockerfile:
# syntax=docker/dockerfile:1
FROM python:3
WORKDIR /usr/src/app
RUN apt-get update
RUN apt-get install -y libgdal-dev gdal-bin netcat
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
COPY /django/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY /django/django-entrypoint.sh /django-entrypoint.sh
RUN chmod +x /django-entrypoint.sh
COPY django /usr/src/app
ENTRYPOINT ["/django-entrypoint.sh"]
And the entrypoint:
#!/bin/sh
if [ "$POSTGRES_NAME" = "postgres" ]
then
echo "Waiting for Postgres..."
while ! nc -z $POSTGRES_HOST $POSTGRES_PORT; do
sleep 0.1
done
echo "PostgreSQL started"
fi
ls
# python manage.py flush --no-input
python manage.py migrate --no-input
python manage.py collectstatic --no-input
exec "$#"
In my files (local), I do not seem to see the '/static/' folder to be generated. How is this? I have check that static in backend and nginx by ssh in the container and the static folders were empty. In the logs, collectstatic was executed without an error with this message:
backend | 173 static files copied to '/static'.
You use a Docker named volume to hold the static files
volumes:
- static:/usr/src/app/static
# ^^^^^^
# a volume name, not a host path
This named volume only exists inside Docker's storage; you will not see its content on your host system or in your local source tree.
This isn't a problem for the setup you're describing here: since you're re-running collectstatic every time the container starts up, and the volume contents hide the image contents in this directory, there's no particular need for the files to exist in source control or your host filesystem. If you did need them, you could presumably run manage.py collectstatic in a non-Docker virtual environment.
Try by adding the following command in Dockerfile and re-build image.
RUN python manage.py collectstatic --noinput
You can place it after RUN pip install --no-cache-dir -r requirements.txt
Related
So I am using Django + react with nginx both on backend and frontend, containerized in docker. The following image will clarify how I want to serve the whole application:
Having been googling but couldn't make sense of the solutions. Issue is that Nginx in frontend not connecting with nginx on backend on port 8082.
Following are docker, nginx and docker-compose files.
Nginx configurations for frontend:
upstream react {
server reactapp:3000;
}
server {
listen 80;
client_max_body_size 100M;
proxy_set_header X-Forwarded-Proto $scheme;
location / {
root /usr/share/nginx/html;
}
location /add-to-waiting/ {
proxy_pass http://0.0.0.0:8082;
}
}
Dockerfile for react and nginx for frontend:
# build environment
FROM node as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm i --silent
RUN npm install react-scripts#3.4.1 -g --silent
COPY . ./
RUN npm run build
# production environment
FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]
docker-compose.yml for frontend:
services:
frontend:
build: .
ports:
- "8090:80"
container_name: irisfrontend
Nginx configurations for backend
upstream django {
server website:8000;
}
server {
listen 80;
client_max_body_size 100M;
proxy_set_header X-Forwarded-Proto $scheme;
location / {
proxy_pass http://django;
}
location /media/ {
alias /app/media/;
}
location /static/ {
alias /app/forex/static/admin/;
}
}
Dockerfile for nginx in backend:
FROM nginx:1.19.0
COPY ./default.conf /etc/nginx/conf.d/default.conf
Dockerfile for gunicorn in backend:
FROM python:3
ADD requirements.txt /app/requirements.txt
ADD . /app
WORKDIR /app
EXPOSE 8000:8000
RUN pip install --upgrade pip && pip install -r /app/requirements.txt
RUN python manage.py collectstatic --no-input --settings=forex.settings.production
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "forex.wsgi:application", "DJANGO_SETTINGS_MODULE=forex.settings.production"]
docker-compose.yml for backend:
services:
db:
build: ./db
website:
build:
context: .
dockerfile: Dockerfile.app
env_file:
- env
container_name: website_container_8
volumes:
- static:/app/forex/static/admin/
depends_on:
- db
nginx:
build: ./nginx
volumes:
- static:/app/forex/static/admin/
ports:
- "8082:80"
depends_on:
- website
volumes:
static:
What changes do I need to make to successfully do a post request from frontend nginx to backend nginx?
Include a network for both containers so that they can communicate.
services:
db:
build: ./db
website:
build:
context: .
dockerfile: Dockerfile.app
env_file:
- env
container_name: website_container_8
volumes:
-
static:/app/forex/static/admin/
depends_on:
- db
networks:
- nettest
nginx:
build: ./nginx
volumes:
-
static:/app/forex/static/admin/
ports:
- "8082:80"
depends_on:
- website
networks:
- nettest
volumes:
static:
networks:
nettest:
I am trying to dockerize a django project with postgres, gunicorn and nginx. My problem is that static files are not served. However in browser console I see all static files being loaded properly (code 200). Also I can easily access any static file directly i.e. 127.0.0.1:8080/static/admin/.../base.css. Nginx doesn't show any errors in console either. What makes it even more strange for me, my redoc.yaml is loaded properly.
Here is part of my settings.py with static:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
Here is my main Dockerfile:
FROM python:latest
RUN mkdir /code
COPY requirements.txt /code
RUN pip install -r /code/requirements.txt
COPY . /code
WORKDIR /code
CMD gunicorn api_yamdb.wsgi:application --bind 0.0.0.0:8000
Here is the Dockerfile for nginx:
FROM nginx:latest
COPY nginx/nginx.conf /etc/nginx/nginx.conf
Here is the nginx.conf file:
events {}
http {
server {
location /static/ {
root /etc/nginx/html/;
}
location / {
proxy_pass http://web:8000;
}
}
}
And finally here is my docker-compose:
version: '3.8'
volumes:
postgres_data:
static:
services:
db:
image: postgres:latest
volumes:
- postgres_data:/var/lib/postgresql/data/
env_file:
- ./.env
web:
build: .
restart: always
command: gunicorn api_yamdb.wsgi:application --bind 0.0.0.0:8000
volumes:
- static:/static
ports:
- "8000:8000"
depends_on:
- db
env_file:
- ./.env
nginx:
build:
context: .
dockerfile: nginx/Dockerfile
ports:
- "8080:80"
volumes:
- ./static:/etc/nginx/html/static
Any help is welcome. Thank you.
This can be fixed by adding include mime.types; into http section of nginx.conf
Sorry if it the answer seems obvious, but I've been bashing my head for the past couple of hours.
I've been following multiple tutorials trying to dockerize my application. No matter what combination of url:port or just url I tried I can't access the pages.
I have zero clue what am I doing wrong. I am assuming the following:
NGINX config plain wrong. How can upstream web know what's web? I assume docker exposes it, but unsure whether this is correct.
web container not exposing address and port properly?
I tried multipled settings, but non work.
I have the following:
Dockerfile
FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
ADD ./django.conf /etc/nginx/conf.d/default.conf
#COPY ./django.conf /etc/nginx/sites-available/
#RUN ln -s /etc/nginx/sites-available/django.conf /etc/nginx/sites-enabled
docker-compose.yml
version: '3'
services:
db:
image: postgres:9.6
ports:
- "5432:5432"
environment:
- POSTGRES_USER=random_user
- POSTGRES_PASSWORD=random_password
redis:
restart: always
image: redis:4.0
expose:
- "6379"
nginx:
image: nginx:1.14.0
container_name: nginx01
ports:
- "8000:8000"
volumes:
- ./code
depends_on:
- web
web:
build: .
container_name: backend-api
command: bash -c "python manage.py migrate && python manage.py collectstatic --noinput && gunicorn ops4_backend.wsgi -b 0.0.0.0:8000"
depends_on:
- db
volumes:
- ./code
expose:
- "8000"
restart: always
django.conf
upstream web {
ip_hash;
server web:8000;
}
# portal
server {
location / {
proxy_pass http://web:8000;
}
listen 8000;
server_name localhost;
location /static {
autoindex on;
alias /src/static/;
}
}
docker ps -a
I was doing almost the same task yesterday, and the only valuable difference I see is that you include django.conf in Django container, not in nginx one. I have following volume in nginx section of docker-compose.yml:
- ./nginx:/etc/nginx/conf.d (where ./nginx is the folder with django.conf)
EDIT: here is my docker-compose.yml:
version: '3'
services:
nginx:
image: nginx
restart: always
ports:
- "80:8000"
volumes:
- ./nginx:/etc/nginx/conf.d
- ./static_cdn:/static
depends_on:
- web
db:
image: postgres
restart: always
web:
build: .
restart: always
command: bash -c "python3 manage.py makemigrations && python3 manage.py migrate && python3 manage.py collectstatic --no-input && gunicorn core.wsgi -b 0.0.0.0:8000"
volumes:
- .:/code
expose:
- "8000"
depends_on:
- db
django.conf:
upstream web {
ip_hash;
server web:8000;
}
server {
location /static/ {
alias /static/;
}
location / {
proxy_pass http://web/;
}
listen 8000;
server_name localhost;
}
With this setup nginx is available at 127.0.0.1:80 or just 127.0.0.1 as 80 is default http port.
There are so many wrong things, please use this configuration. and then change it step by step toward your specific needs.
also checkout this page that talks about Nginx Docker Configurations because one of your main problems is that you are not exposing django nginx conf that you make:
ADD ./django.conf /etc/nginx/conf.d/default.conf
to nginx container.
so nginx does not know how to map your configs.
I'm new to Docker and setting up my first Django application using Docker
My application path looks like
app
|- helloworld
|- __init__.py
|- manage.py
|- static_cdn
|- static_root
|- config
|- nginx
|- nginx.conf
|- Dockerfile
|- docker-compose.yml
|- requirements.txt
|- start.sh
the contents of Docerfile
FROM ubuntu:18.04
# -- Install Pipenv:
FROM python:3
ENV PYTHONUNBUFFERED 1
ENV LC_ALL C.UTF-8
ENV LANG C.UTF-8
# -- Install Application into container:
RUN set -ex && mkdir /app
WORKDIR /app
ADD requirements.txt /app/
RUN pip install -r requirements.txt
# -- Adding dependencies:
ADD . /app/
contents of docker-compose.yml
version: '3'
services:
nginx:
image: nginx:latest
ports:
- "9010:9010"
volumes:
- .:/app
- ./config/nginx:/etc/nginx/conf.d
- ./static_cdn:/static
depends_on:
- web
web:
build: .
command: ./start.sh
volumes:
- .:/app
- ./static_cdn:/static
ports:
- "9010:9010"
depends_on:
- db
expose:
- "9010"
db:
image: postgres
contents of config/nginx/nginx.conf
upstream web {
ip_hash;
server web:9010;
}
server {
location /static {
autoindex on;
alias /static/
}
location / {
proxy_pass http://127.0.0.1;
}
listen 9011;
server_name localhost;
}
contents of start.sh
#!/usr/bin/env bash
# Start Gunicorn processes
echo --: Starting application build
echo --: Creating migration
exec python3 manage.py makemigrations
echo ------: makemigrations complete
echo --: Running migration
exec python3 manage.py migrate
echo ------: migrate complete
echo --: Running collectstatic
exec python3 manage.py collectstatic
echo ------: collectstatic complete
echo Starting Gunicorn.
exec gunicorn helloworld.wsgi:application \
--bind 0.0.0.0:9010 \
--workers 3
Now, when I build using docker
docker-compose up --build
It gives error as
ERROR: for nginx Cannot start service nginx: driver failed
programming external connectivity on endpoint koober_nginx_1
(8ea5c084a7283a16afbf136a73dc4b27d9cae35fe14d735b83199ad5d0e03431):
Bind for 0.0.0.0:9010 failed: port is already allocated
I have followed few tutorials to create those Docker files and nginx conf file.
1. How can I solve above issue.
2. Do I need to use FROM ubuntu:18.04 with above configuration?
Edit 2
Now, it stuck after creating migration from start.sh commands
You can't allocate port 9010 of your host for both services.
This is what you're doing in the ports section of declaration of service nginx and web.
Moreover, by default nginx will listen to port 80 and 443 for https.
You can keep it like that and publish to a different port on your host. See how to use port keyword in docker-compose :
https://docs.docker.com/compose/compose-file/#ports
Maybe you want something more like that:
version: '3'
services:
nginx:
image: nginx:latest
ports:
- "10080:80"
- "10443:443"
volumes:
- .:/app
- ./config/nginx:/etc/nginx/conf.d
- ./static_cdn:/static
depends_on:
- web
web:
build: .
command: ./start.sh
container_name: "web-app"
volumes:
- .:/app
- ./static_cdn:/static
expose:
- "9010"
depends_on:
- db
db:
image: postgres
contents of config/nginx/nginx.conf
upstream web {
ip_hash;
server web-app:9010;
}
server {
location /static {
autoindex on;
alias /static/
}
location / {
proxy_pass http://web;
}
listen 80;
server_name localhost;
}
Concerning your last question, you could go for an official Python image from the Docker hub Python repository or start from any other base image like debian:jessie-slim from Debian official repository or keep the Ubuntu 18.04 image
For me, stopping/restarting the NGINX server worked.
To stop Nginx, use the following command:
sudo systemctl stop nginx
To start Nginx when it is stopped, use the following command:
sudo systemctl start nginx
To restart Nginx, use the following command:
sudo systemctl restart nginx
To reload Nginx after making configuration changes, use the following command:
sudo systemctl reload nginx
This is probably the millionth django+nginx post, but since I didn't find an answer after more than 5 hours here it goes:
My issue is that not all static files get served, only some. The whole thing runs inside Docker where I run
RUN python manage.py collectstatic --noinput;
RUN python manage.py makemigrations;
RUN python manage.py migrate;
on each start, but it does not serve my new .js and .css files although they are in the same directories as the old ones.
I also see the message:
132 static files copied to '/static'.
and above that is the list of files being copied there, including the new ones.
Project Structure:
/djangoapp
/app
/static
/css
/js
/django
/Dockerfile
/docker-compose
settings.py:
DEBUG = False
STATIC_URL = '/static/'
STATIC_ROOT = '/static'
nginx.conf:
upstream web {
ip_hash;
server web:8000;
}
server {
location /static {
autoindex on;
alias /static;
}
location / {
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
proxy_pass http://web/;
}
listen 8000;
server_name localhost;
}
Why aren't all static files being served?
EDIT:
Dockerfile:
FROM python:3.6.4-onbuild
RUN mkdir /config;
RUN mkdir /src;
COPY . /src
WORKDIR /src
RUN python manage.py collectstatic --noinput;
RUN python manage.py makemigrations;
RUN python manage.py migrate;
RUN chmod 775 -R /static
#this shows that the new files reside with the others in the same directory
RUN ls -R /static/
CMD gunicorn WebInterface.wsgi -b 0.0.0.0:8000 --timeout 3600
docker-compose.yml:
version : '3'
services:
web:
build: ./WebInterface
container_name: WebDocker
volumes:
- static-content:/static
expose:
- "80"
nginx:
image: nginx:1.12.2
container_name: NGINXDocker
ports:
- "8000:8000"
volumes:
- ./WebInterface:/src
- ./config/nginx:/etc/nginx/conf.d/
- static-content:/static
depends_on:
- web
volumes:
static-content:
Ok, with the additional info I think I know what's going on.
You run your python script to generate static files (which I assume it does) on build. On run, you mount the directory, so it will overwrite everything in the static directory.
Either don't mount it or add the scripts
python manage.py collectstatic --noinput;
python manage.py makemigrations;
python manage.py migrate;
in the entrypoint (https://docs.docker.com/engine/reference/builder/#entrypoint)
Also, the mounting of static into the nginx container doesn't do anything since you are only reverse proxying into the django container and not giving a root path. Or if it does work by some coincident, I'm not sure if it would get the newly generated files on startup.
Hope this helps, had a lot of fun with that stuff when I started with docker...
A workaround for now is to create the static folder on my local machine and then transfer the files to the desired position inside docker-compose.
When I find a real solution, on why collect static is not working within docker I will update this
Edit: Solution provided by LevinM
updated the Dockerfile (This only provides the image and installs python libraries from requirements.txt due to the 'onbuild' parameter):
FROM python:3.6.4-onbuild
updated docker-compose.yml:
version : '3'
services:
web:
build: ./WebInterface
entrypoint: bash -c "python manage.py collectstatic --noinput && python manage.py makemigrations && python manage.py migrate && gunicorn WebInterface.wsgi -b 0.0.0.0:8000 --timeout 3600";
container_name: WebDocker
volumes:
- ./WebInterface:/src
- static-content:/static
expose:
- "80"
nginx:
image: nginx:1.12.2
container_name: NGINXDocker
ports:
- "8000:8000"
volumes:
- ./WebInterface:/src
- ./config/nginx:/etc/nginx/conf.d/
- static-content:/static
depends_on:
- web
volumes:
static-content: