diff --git a/Dockerfile b/Dockerfile index 3a3de61..6300614 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM alpine:3.19 # FROM alpine:3.22 -EXPOSE 3031 +EXPOSE 8000 RUN addgroup -S uwsgi && \ adduser -S -G uwsgi uwsgi && \ @@ -13,6 +13,7 @@ WORKDIR /app RUN apk add --no-cache \ uwsgi-python3 \ + uwsgi-http \ python3 \ py3-pip \ npm \ @@ -44,13 +45,12 @@ COPY Pipfile* ./ RUN PIP_BREAK_SYSTEM_PACKAGES=1 pipenv install --system --deploy COPY . . -# RUN chown -R uwsgi:uwsgi /app -# RUN chmod -R 555 /app -# TODO: more fleshed out uwsgi configuration - -ENTRYPOINT [ "/app/entrypoint.sh", \ +ENTRYPOINT [ "/app/entrypoint.sh", \ "--env", "HOME=/home/uwsgi", \ + "--http-socket", "0.0.0.0:8000", \ "--uid", "uwsgi", \ + "--gid", "uwsgi", \ "--plugins", "python3", \ - "--wsgi", "wsgi:application" ] \ No newline at end of file + "--need-app", \ + "--wsgi-file", "wsgi.py" ] \ No newline at end of file diff --git a/README.md b/README.md index bf21f04..a8117f1 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,29 @@ Configuration may also be passed by setting environment variables. All supporte ### Docker -A Dockerfile + compose file are provided for easy setup, running the application via uWSGI and exposing it via nginx on port 8000. To start: +#### For Development - docker compose up -d - docker compose exec app -- flask db upgrade +A Dockerfile + compose file are provided for easy setup, running the application via uWSGI on HTTP port 8000. To start, run `docker compose up -d`. This starts the necessary services, and a locally-built app container running several processes that will automatically reload when Python code is changed. + +#### For Development - Latest Version + +An additional compose file is provided that runs the latest version of the pre-built image with a slightly more robust uWSGI configuration, and does not mount the local repository into the image (and thus won't auto-reload code or reflect changes to the local repository). To start, run `docker compose -f docker-compose.yaml -f docker-compose-prod.yaml up -d`. + +#### For Production + +For a completely custom Docker setup, use one of the following images: + + * `ghcr.io/basementcat/fruitstand:latest` - Latest tagged version + * `ghcr.io/basementcat/fruitstand:master` - Latest master branch + * `ghcr.io/basementcat/fruitstand:develop` - Development branch, likely to be ahead of latest/master, may be broken. + +The container can be configured using the environment variables above, or a `.env` file if present. As above, the application will run on HTTP port 8000 with a minimal uWSGI configuration; you will have to supply any additional configuration as an alternative command or replace the entryoint if you want a different protocol like WSGI. + +This approach is recommended for a "real" (i.e. non-development) deployment, as it avoids using the default database passwords and allows for the most flexibility in configuration. + +#### Database Migrations + +The entrypoint script automatically waits for the database to be ready, and then runs database migrations. If this behavior is not desired, it can be disabled by setting the environment variable `FRUITSTAND_NO_AUTO_MIGRATE=1` (any non-empty value is acceptable), in which case migrations must be run manually with `docker compose exec app -- flask db upgrade`. ### Local development environment @@ -63,6 +82,8 @@ In order to run locally you'll need to set up a minimal configuration as explain flask db upgrade flask run +When pulling a new version, database migrations may be required - run `flask db upgrade` again to apply them if any new migrations are present. + ## Building To build assets for the main application, as well as any discovered screens: @@ -74,12 +95,6 @@ To build assets for the main application, as well as any discovered screens: To build within Docker if you do not set up a local development environment, prefix the commands with `docker compose exec app --`, for example `docker compose exec app -- flask compile sass` -## Docker image - -The image built by the Dockerfile runs the application via uWSGI with a minimal configuration; see the docker-compose file for the arguments used to run in WSGI protocol mode. For alternate deployments, various options can be tuned by setting environment variables or passing command line options, or providing a config file - see the uWSGI documentation. - -For example, to run via HTTP (for example, for a reverse proxy that does not speak the WSGI protocol), you can pass a command like `--http=0.0.0.0:8080 --master --processes=4` - ## Sources/Attributions Heavily inspired by: diff --git a/docker-compose-prod.yaml b/docker-compose-prod.yaml new file mode 100644 index 0000000..06ba136 --- /dev/null +++ b/docker-compose-prod.yaml @@ -0,0 +1,15 @@ +services: + app: + build: !reset null + image: ghcr.io/basementcat/fruitstand:master + command: [ + '--master', + '--processes=4', + '--lazy-apps', + '--cheaper-algo=spare', + '--cheaper=2', + '--cheaper-initial=5', + '--workers=5', + '--cheaper-step=1', + ] + volumes: !reset [] diff --git a/docker-compose.yaml b/docker-compose.yaml index f42d1a3..86f0513 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,30 +1,21 @@ services: - web: - image: nginx:1.29-alpine - restart: always - depends_on: - - app - ports: - - 8000:80 - volumes: - - ./local-nginx.conf:/etc/nginx/conf.d/default.conf:ro - app: build: . command: [ + '--master', '--processes=4', '--py-autoreload=1', - '--socket=0.0.0.0:3031', - '--protocol=uwsgi', - '--need-app', ] restart: always depends_on: - db + ports: + - 8000:8000 environment: - FRUITSTAND_SECRET_KEY=lkasdjfalsdkjflskjdklsjdflk - FRUITSTAND_SQLALCHEMY_DATABASE_URI=mysql+pymysql://fruitstand:password@db:3306/fruitstand - - FRUITSTAND_INTERNAL_WEB_HOST=web + - FRUITSTAND_INTERNAL_WEB_HOST=app:8000 + - FRUITSTAND_CACHE_DRIVER=database volumes: - .:/app @@ -48,4 +39,4 @@ services: # - '1025:1025' # - '8025:8025' volumes: - db-data: {} \ No newline at end of file + db-data: {} diff --git a/local-nginx.conf b/local-nginx.conf deleted file mode 100644 index 3b1885c..0000000 --- a/local-nginx.conf +++ /dev/null @@ -1,11 +0,0 @@ -server { - listen 80; - root /usr/share/nginx/html; - location / { - try_files $uri @wsgi; - } - location @wsgi { - include uwsgi_params; - uwsgi_pass app:3031; - } -} \ No newline at end of file