From aad8abd0c78f6c0866759d05b29504e9c05899d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A6var=20=C3=96fj=C3=B6r=C3=B0=20Magn=C3=BAsson?= Date: Thu, 27 Oct 2022 09:54:43 +0000 Subject: [PATCH 1/3] Add support for docker-compose. This makes it easier to manage the container with volumes to make the database persistent, and for developers to make changes to the editor guide code and test them out on the running container. --- Dockerfile.localdev | 98 +++++++++++++++++++++++++++++++++++++++++++++ Makefile | 13 ++++-- docker-compose.yml | 24 +++++++++++ 3 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 Dockerfile.localdev create mode 100644 docker-compose.yml diff --git a/Dockerfile.localdev b/Dockerfile.localdev new file mode 100644 index 00000000..aca208b3 --- /dev/null +++ b/Dockerfile.localdev @@ -0,0 +1,98 @@ +# (Keep the version in sync with the node install below) +FROM node:16 as frontend + +# Make build & post-install scripts behave as if we were in a CI environment (e.g. for logging verbosity purposes). +ARG CI=true + +# Install front-end dependencies. +COPY package.json package-lock.json webpack.config.js ./ +RUN npm ci + +# Compile static files +COPY ./apps/frontend/static_src/ ./apps/frontend/static_src/ +RUN npm run build + + +# We use Debian images because they are considered more stable than the alpine +# ones becase they use a different C compiler. Debian images also come with +# all useful packages required for image manipulation out of the box. They +# however weigh a lot, approx. up to 1.5GiB per built image. +FROM python:3.9 as production + +ARG POETRY_HOME=/opt/poetry +ARG POETRY_INSTALL_ARGS="" + +# IMPORTANT: Remember to review this when upgrading +ARG POETRY_VERSION=1.2.2 + +# Install dependencies in a virtualenv +ENV VIRTUAL_ENV=/venv + +RUN useradd guide --create-home && mkdir /app $VIRTUAL_ENV && chown -R guide /app $VIRTUAL_ENV + +WORKDIR /app + +# Set default environment variables. They are used at build time and runtime. +# If you specify your own environment variables on Heroku, they will +# override the ones set here. The ones below serve as sane defaults only. +# * PATH - Make sure that Poetry is on the PATH, along with our venv +# * PYTHONUNBUFFERED - This is useful so Python does not hold any messages +# from being output. +# https://docs.python.org/3.9/using/cmdline.html#envvar-PYTHONUNBUFFERED +# https://docs.python.org/3.9/using/cmdline.html#cmdoption-u +# * DJANGO_SETTINGS_MODULE - default settings used in the container. +# * PORT - default port used. Please match with EXPOSE. +# Heroku will ignore EXPOSE and only set PORT variable. PORT variable is +# read/used by Gunicorn. +# * WEB_CONCURRENCY - number of workers used by Gunicorn. The variable is +# read by Gunicorn. +# * GUNICORN_CMD_ARGS - additional arguments to be passed to Gunicorn. This +# variable is read by Gunicorn +ENV PATH=${POETRY_HOME}/bin:$VIRTUAL_ENV/bin:$PATH \ + POETRY_INSTALL_ARGS=${POETRY_INSTALL_ARGS} \ + PYTHONUNBUFFERED=1 \ + DJANGO_SETTINGS_MODULE=apps.guide.settings.production \ + PORT=8000 \ + WEB_CONCURRENCY=3 \ + GUNICORN_CMD_ARGS="-c gunicorn-conf.py --max-requests 1200 --max-requests-jitter 50 --access-logfile - --timeout 25" + +# Make $BUILD_ENV available at runtime +ARG BUILD_ENV +ENV BUILD_ENV=${BUILD_ENV} + +# Port exposed by this container. Should default to the port used by your WSGI +# server (Gunicorn). Heroku will ignore this. +EXPOSE 8000 + +# Install poetry using the installer (keeps Poetry's dependencies isolated from the app's) +# chown protects us against cases where files downloaded by poetry have invalid ownership +# chmod ensures poetry dependencies are accessible when packages are installed +RUN curl -sSL https://install.python-poetry.org | python3 - +RUN chown -R root:root ${POETRY_HOME} && \ + chmod -R 0755 ${POETRY_HOME} + +# Don't use the root user as it's an anti-pattern and Heroku does not run +# containers as root either. +# https://devcenter.heroku.com/articles/container-registry-and-runtime#dockerfile-commands-and-runtime +USER guide + +# Install your app's Python requirements. +RUN python -m venv $VIRTUAL_ENV +COPY --chown=guide pyproject.toml poetry.lock ./ +RUN pip install --upgrade pip && poetry install ${POETRY_INSTALL_ARGS} --no-root + +COPY --chown=guide --from=frontend ./apps/frontend/static ./apps/frontend/static + +# Copy application code. +COPY --chown=guide . . + +RUN poetry install ${POETRY_INSTALL_ARGS} + +# Collect static. This command will move static files from application +# directories and "static_compiled" folder to the main static directory that +# will be served by the WSGI server. +RUN SECRET_KEY=none python manage.py collectstatic --noinput --clear + +# Run the WSGI server. It reads GUNICORN_CMD_ARGS, PORT and WEB_CONCURRENCY +# environment variable hence we don't specify a lot options below. +CMD gunicorn apps.guide.wsgi:application diff --git a/Makefile b/Makefile index 1af312aa..5a8439e9 100644 --- a/Makefile +++ b/Makefile @@ -45,13 +45,18 @@ run: poetry run python manage.py runserver docker-build: - docker build -t guide:latest --build-arg POETRY_INSTALL_ARGS="" -f Dockerfile . + docker-compose build docker-run: - docker run --name guide_latest -p ${PORT}:${PORT} --env-file .env guide:latest sh -c 'poetry run python manage.py runserver 0.0.0.0:${PORT}' + docker-compose up docker-exec: - docker exec -it guide_latest /bin/bash + docker-compose exec web bash docker-init: - docker exec -it guide_latest /bin/bash -c "make backend" + docker-compose exec web poetry install + docker-compose exec web poetry run python manage.py migrate + docker-compose exec web poetry run python manage.py createcachetable + docker-compose exec web poetry run python manage.py createsuperuser + docker-compose exec web poetry run python manage.py buildfixtures + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..3d39ce70 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +version: '3' + +volumes: + node_modules: +services: + web: + build: + context: . + dockerfile: Dockerfile.localdev + extra_hosts: + - "host.docker.internal:host-gateway" + command: poetry run python manage.py runserver 0.0.0.0:${PORT:-8000} + volumes: + - .:/app:delegated,rw + - node_modules:/app/node_modules/ + ports: + - "${PORT:-8000}:${PORT:-8000}" + environment: + SECRET_KEY: $SECRET_KEY + ALLOWED_HOSTS: $ALLOWED_HOSTS + PORT: ${PORT:-8000} + DJANGO_SETTINGS_MODULE: ${DJANGO_SETTINGS_MODULE:-apps.guide.settings.dev} + + From e095a3c91abaf51c2ce1ab878ce4eb5e54248b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A6var=20=C3=96fj=C3=B6r=C3=B0=20Magn=C3=BAsson?= Date: Thu, 27 Oct 2022 09:58:54 +0000 Subject: [PATCH 2/3] Add requirements to the Readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4a92683d..7d5e2737 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ To activate Poetry's virtual environment, run: ### Setting up development with Docker +**Requirements:** [Docker](https://www.docker.com/) and Docker Compose (Docker Compose is included with Docker Desktop for Mac and Windows). + 1. Create a `.env` file in the project root containing these variables, you can adjust the values to your preferences: ``` ALLOWED_HOSTS=localhost From 8c677f61b335b51154a38d0c32e5bf26f4b64ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A6var=20=C3=96fj=C3=B6r=C3=B0=20Magn=C3=BAsson?= Date: Thu, 27 Oct 2022 10:08:59 +0000 Subject: [PATCH 3/3] Clarifying container shell access, linting docker-compose.yml. Adding the frontend container to be able to run npm commands --- Makefile | 5 ++++- README.md | 8 ++++++++ docker-compose.yml | 17 +++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 5a8439e9..c4eb8911 100644 --- a/Makefile +++ b/Makefile @@ -50,9 +50,12 @@ docker-build: docker-run: docker-compose up -docker-exec: +docker-shell: docker-compose exec web bash +docker-shell-frontend: + docker-compose exec frontend bash + docker-init: docker-compose exec web poetry install docker-compose exec web poetry run python manage.py migrate diff --git a/README.md b/README.md index 7d5e2737..33b8c04d 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,14 @@ To activate Poetry's virtual environment, run: 4. Run the init script in the container: `make docker-init` 5. You should now have access to the project in your browser at `http://localhost:8000` +To access the app container, run: + +`make docker-shell` + +To access the frontend container to run linting, etc: + +`make docker-shell-frontend` + # Gitpod With Gitpod you can deploy a ready-to-code Wagtail Guide development environment with a single click to evaluate the code. diff --git a/docker-compose.yml b/docker-compose.yml index 3d39ce70..83d84bac 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,17 +8,26 @@ services: context: . dockerfile: Dockerfile.localdev extra_hosts: - - "host.docker.internal:host-gateway" + - 'host.docker.internal:host-gateway' command: poetry run python manage.py runserver 0.0.0.0:${PORT:-8000} volumes: - .:/app:delegated,rw - node_modules:/app/node_modules/ ports: - - "${PORT:-8000}:${PORT:-8000}" + - '${PORT:-8000}:${PORT:-8000}' environment: SECRET_KEY: $SECRET_KEY ALLOWED_HOSTS: $ALLOWED_HOSTS PORT: ${PORT:-8000} DJANGO_SETTINGS_MODULE: ${DJANGO_SETTINGS_MODULE:-apps.guide.settings.dev} - - + frontend: + build: + context: . + dockerfile: Dockerfile.localdev + target: frontend + working_dir: /app + volumes: + - ./:/app:cached,rw + - node_modules:/code/node_modules/ + command: tail -f /dev/null + restart: 'no'