whythawk / full-stack-fastapi-postgresql

Full stack, modern web application generator. Using FastAPI, PostgreSQL as database, Nuxt3, Docker, automatic HTTPS and more.
MIT License
231 stars 47 forks source link

build.sh throws error: COPY failed: stat app/public: file does not exist #34

Closed roland-jungwirth closed 11 months ago

roland-jungwirth commented 1 year ago

I am (still) playing around with this code base and am trying to run it in production (as is) on a DigitalOcean droplet. I have this successfully running locally, but when I "Build your app images", the command

TAG=prod FRONTEND_ENV=production bash ./scripts/build.sh

returns the following error:

Step 47/55 : COPY --from=build /app/public ./public
ERROR: Service 'frontend' failed to build: COPY failed: stat app/public: file does not exist

This comes from line 50 in frontend/Dockerfile:

COPY --from=build /app/public ./public

Checking the code base, there is no "frontend/public" folder. Any idea what I have done wrong?

Also, there is inconsistency in how to build the images. In the project slug (https://github.com/whythawk/full-stack-fastapi-postgresql/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/README.md) the command is

TAG=prod FRONTEND_ENV=production bash ./scripts/build.sh

whereas the instructions in master (https://github.com/whythawk/full-stack-fastapi-postgresql/blob/master/docs/deployment-guide.md#docker-swarm-mode) is

DOMAIN=example.com TRAEFIK_TAG=example.com STACK_NAME=example-com TAG=prod bash -x scripts/deploy.sh

which one is correct?

roland-jungwirth commented 1 year ago

From my understanding the /frontend/Dockerfile copies everything from the frontend directory to the "/app" directory on the Docker ("build") container in this line line 3: COPY . /app Then it copies all of these files to the "/app" folder in the "run-minimal" container. There is no frontend/public folder, so the error makes sense. I'm not sure why it doesn't fail with the .output folder, which doesn't exist either. How can I fix the build error?

turukawa commented 1 year ago

Hi @roland-jungwirth

If you compare this:

DOMAIN=example.com TRAEFIK_TAG=example.com STACK_NAME=example-com TAG=prod bash -x scripts/deploy.sh

To:

TAG=prod FRONTEND_ENV=production bash ./scripts/build.sh

You should see you're setting a bunch of variables (and there's a build and deploy script). Most of those are in the .env file (like STACK_NAME) but what you're explicitly doing is telling the script whether this is prod or dev or so on. So both approaches are correct but, since some of the parameters are redundant, I don't list them again, just the ones you absolutely need.

Your second issue is one that needs fixing and I need to review it, but it's a simple'ish problem.

The difference between the frontend environment running in dev mode vs production is that production runs on Alpine, which is stripped down to the absolute minimum to be as fast as possible on limited hardware. But ... that means that you need to explicitly tell the build what directories you want to copy across into the container.

If you look in the Docker file for the frontend, you'll see all the directories listed there.

The easy fix is simply to delete this line:

COPY --from=build /app/public ./public

I'm not sure why it doesn't fail on the other one ... the mysteries of computers.

roland-jungwirth commented 1 year ago

Hi @turukawa, thank you for your answer. Makes sense with the build/deploy script.

So if I don't copy the public folder, that isn't needed?

turukawa commented 1 year ago

If don't have a public folder, then no.

The Docker script must always reflect your build. It's not fire-and-forget. If you try copy things you don't have, it'll crash on build. If you don't copy things you do need, it'll fail in production ...

Same goes for your dependencies, and pinning their versions. Keep your Docker file in sync with your build. It's good in some ways, because it keeps you honest ;p