Django - collectstatic from deploy release_command success but staticfile folder not found

Hello,

I deployed a django app using a Dockerfile, with collectstatic in the deploy release_command.

When I deploy, it is mentioned that static files are copied to /app/staticfiles as expected:

2356 static files copied to '/app/staticfiles', 6920 post-processed.

but they are not available to django:

2022-09-06T07:26:05Z app[08b1ad0c] cdg [info]  File "/usr/local/lib/python3.9/site-packages/django/contrib/staticfiles/storage.py", line 472, in stored_name
2022-09-06T07:26:05Z app[08b1ad0c] cdg [info]    raise ValueError(
2022-09-06T07:26:05Z app[08b1ad0c] cdg [info]ValueError: Missing staticfiles manifest entry for 'contrib/bootstrap/bootstrap.min.css'

when I ssh the node, there is no staticfiles in app folder.

If I run manually python manage.py collectstatic from ssh console and restart gunicorn then it works

Any idea of what I am missing?

Some extracts of my settings.py related to whitenoise (DEBUG is False):

...
STATIC_ROOT = os.path.abspath(os.path.join(BASE_DIR, 'staticfiles'))
...
if not DEBUG:
   MIDDLEWARE.insert(1,'whitenoise.middleware.WhiteNoiseMiddleware')
   STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
...

fly.toml:

app = "XXXXX"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[env]

[deploy]
  release_command = "bash -c \"python manage.py migrate && python manage.py collectstatic --noinput\""

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

Dockerfile:

ARG PYTHON_VERSION=3.9

FROM python:${PYTHON_VERSION}

RUN apt-get update && apt-get install -y \
    python3-pip \
    python3-venv \
    python3-dev \
    python3-setuptools \
    python3-wheel

RUN mkdir -p /app
WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 8080

CMD ["gunicorn", "--bind", ":8080", "--workers", "1", "stones.wsgi"]

Thanks!

Ok, I found the issue by reading the docs a bit more carefully. The answer may be useful to others.

Durnig deploy release_command, " Changes made to the filesystem on the temporary VM will not be retained or deployed. If you need to modify persistent volumes or configure your application, consider making use of CMD or ENTRYPOINT in your Dockerfile.".

Hence, the call to collectstatic should not be done as deploy release_command but rather in the Dockerfile. We cannot easily call collectstatic using RUN as there is no access to database (by default, secret environment variable is not set during build), so I ended up modifying the CMD:

CMD ["/bin/bash", "-c", "python manage.py collectstatic --noinput; gunicorn --bind :8080 --workers 1 stones.wsgi"]

And this works.