Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for docker-compose. #221

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions Dockerfile.localdev
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# (Keep the version in sync with the node install below)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: What's the value in having a separate dockerfile? The main one ought to work just fine for this.

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
18 changes: 13 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,21 @@ 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-shell:
docker-compose exec web bash

docker-shell-frontend:
docker-compose exec frontend bash

docker-init:
docker exec -it guide_latest /bin/bash -c "make backend"
docker-compose exec web poetry install
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Why are dependencies being run like this? It happens during build time, which is probably fine.

Suggested change
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

10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -74,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.
Expand Down
33 changes: 33 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: If we always override the command here, why not just put it in the dockerfile?

volumes:
- .:/app:delegated,rw
- node_modules:/app/node_modules/
ports:
- '${PORT:-8000}:${PORT:-8000}'
environment:
SECRET_KEY: $SECRET_KEY
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we duplicating these to pass them through? I'd recommend either using dummy values, or having docker-compose read from a .env file.

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'