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

Merge project setup with appropriate local dev environment settings #1

Merged
merged 77 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
f10d29c
Configured pytest for dev environment
katporks Nov 2, 2023
dc3fe33
updated wagtail
katporks Nov 2, 2023
235752b
Separated dockerfile, dockercompose builds into different environments
katporks Nov 2, 2023
d824b93
Automated docker-compose migration for local development
katporks Nov 2, 2023
bf8315e
Added make command for refreshing the db
katporks Nov 2, 2023
b73fa89
Added COPYING and LICENSE
katporks Nov 2, 2023
8a3f66b
Wrote README.md
katporks Nov 2, 2023
322d42d
Configuring workflow - hot_osm.yml
katporks Nov 2, 2023
f2693a0
Removed example workflow
katporks Nov 2, 2023
9be6ae2
Changed pytest to pytest-django for db reliant tests
katporks Nov 3, 2023
00db28d
Trying hot_osm github workflow for image builds
katporks Nov 3, 2023
edbcb12
Fix: Added action file to correct directory
katporks Nov 3, 2023
5ae2a8e
Configuring hotosm Image Build workflow
katporks Nov 3, 2023
050de02
Fix: GH actions troubleshoot - removed static files from .dockerignore
katporks Nov 3, 2023
6300058
Automated superuser creation for local environments based .env.dev
katporks Nov 3, 2023
5a33eaf
Updated README to reflect .env.dev superuser creation
katporks Nov 3, 2023
7149d28
Added hotosm's pytest GH workflow
katporks Nov 3, 2023
cd75256
Fix: Removed colon from img tag and replaced it with hyphen
katporks Nov 3, 2023
c489492
Fix: Drew out conditionals in attempt to fix formatting error
katporks Nov 3, 2023
dbf2048
Fix: found the source of tag in image_build.yml
katporks Nov 3, 2023
592ee86
Fix: added build_context and build_dockerfile
katporks Nov 3, 2023
60097f7
Fix: Debugging pytest action through Dockerfile
katporks Nov 4, 2023
5668bd1
Fix: added ci declaration to fix pytest workflow
katporks Nov 4, 2023
80bfa62
Synthesized example .envs into .env.example
katporks Nov 10, 2023
bcc1caa
Added image tag to docker-compose.dev.yml
katporks Nov 10, 2023
11d2c42
Separated workflows for image build and pytest
katporks Nov 10, 2023
0907b84
Switched workflow to test via docker compose
katporks Nov 10, 2023
f9c6610
Formatted branches + added dev env to workflow
katporks Nov 10, 2023
c2dcb86
Streamlined pytest.yml
katporks Nov 10, 2023
b62c193
Removed redundant Dockerfile for previous workflow
katporks Nov 10, 2023
dd37061
Removed pipenv in favour of poetry
katporks Nov 11, 2023
44368df
Removed conditional environments for .env
katporks Nov 11, 2023
83c7d35
Removed references to alternate .env
katporks Nov 11, 2023
e17fad0
Fix: Changed docker service name
katporks Nov 11, 2023
86185e4
Fix: Added wait-for-it and pytest-timeout due to infinite test loop
katporks Nov 11, 2023
36090d8
Fix: Changed script order in Dockerfile
katporks Nov 11, 2023
bbaf88e
Fix: Loading environment from .env in docker-compose
katporks Nov 11, 2023
8d0c0ea
Fix: Corrected example DB_HOST to match docker service
katporks Nov 11, 2023
f8cbf41
Fix: Added time out to wait-for-it.sh
katporks Nov 11, 2023
f0327a7
Fix: Corrected example db port
katporks Nov 11, 2023
cee5e31
Fix: Updated default example values
katporks Nov 11, 2023
769ffa7
Linked postgres variables to .env file
katporks Nov 11, 2023
c0f2c1f
Removed wait-for-it script
katporks Nov 11, 2023
ca50dbb
Added shell command for gh workflow
katporks Nov 14, 2023
379bb4a
Fix: Updated .env.example for substitution
katporks Nov 14, 2023
3fe991c
Updated .gitignore
katporks Nov 15, 2023
7b7956c
Added wait for it command in docker compose
katporks Nov 15, 2023
7a2bce7
Added sleep for 10 seconds before running the server
katporks Nov 15, 2023
4862f85
Added health check to address db timeout
katporks Nov 15, 2023
74639fa
Removed pytest timeout for testing purposes
katporks Nov 15, 2023
a29fb2e
Added missing default values to .env.example
katporks Nov 16, 2023
ec1ba1d
Switched from docker-compose to docker compose
katporks Nov 16, 2023
c00cb08
Added secrets: inherit to workflows
katporks Nov 17, 2023
6607bdf
Separated builds into base and server
katporks Nov 17, 2023
084d80e
Added test build to Dockerfile and test service in docker-compose.dev…
katporks Nov 17, 2023
bbd2205
Added build_target
katporks Nov 17, 2023
53fa061
Added blank compose_command
katporks Nov 17, 2023
5f4e14d
Added gunicorn package
katporks Nov 17, 2023
96dc863
Removed pip install gunicorn
katporks Nov 17, 2023
24f3514
Added permissions to wagtail user for pytest to run
katporks Nov 17, 2023
c630de3
Testing location of pytest as compose_command
katporks Nov 17, 2023
3379af2
Testing pytest compose_command with path st in Dockerfile.dev
katporks Nov 17, 2023
379e2d7
Revert "Testing pytest compose_command with path st in Dockerfile.dev"
katporks Nov 17, 2023
392956c
Revert "Testing location of pytest as compose_command"
katporks Nov 17, 2023
a37ae16
Revert "Added permissions to wagtail user for pytest to run"
katporks Nov 17, 2023
a3be2d0
Removed pip install gunicorn
katporks Nov 17, 2023
f9ddd47
Testing with a failing test
katporks Nov 17, 2023
f97f16a
Revert "Testing with a failing test"
katporks Nov 17, 2023
833067e
Updated poetry dependencies
katporks Nov 17, 2023
5b7ffc2
build: combine dockerfiles into single multistage
spwoodcock Nov 17, 2023
f1e87cd
docs: update refs to Dockerfile.dev
spwoodcock Nov 17, 2023
58f9bf9
build: update compose config to use targets + pinned postgres
spwoodcock Nov 17, 2023
1c202fe
ci: update workflows to use single dockerfile
spwoodcock Nov 17, 2023
f8bde7e
ci(pytest): use web service instead, removed test svc
spwoodcock Nov 17, 2023
615df59
build: fix typo in requirements.txt file
spwoodcock Nov 17, 2023
e1d0916
refactor: add to dockerignore
spwoodcock Nov 17, 2023
e411466
build: fix appuser --> wagtail for dep copy
spwoodcock Nov 17, 2023
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
14 changes: 12 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Django project
/media/
/static/
*.sqlite3

# Python and others
__pycache__
Expand Down Expand Up @@ -37,3 +35,15 @@ wheels/
*.egg-info/
.installed.cfg
*.egg

# Github workflows
.github

# Git
.git

# Docker compose
docker-compose*

# Makefile
Makefile
22 changes: 15 additions & 7 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
SECRET_KEY = ""
ENV=${ENV:-dev}
SECRET_KEY=${SECRET_KEY:-somesuperdupersecretkeyfortesting}

# SECURITY WARNING: define the correct hosts in production!
ALLOWED_HOSTS = ["*"]
ALLOWED_HOSTS=${ALLOWED_HOSTS:-["*"]}

# Superuser creation (override in production)
DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME:-admin}
DJANGO_SUPERUSER_EMAIL=${DJANGO_SUPERUSER_EMAIL:[email protected]}
DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD:-adminpassword}

# Postgres DB settings
DB_NAME = ""
DB_USER = ""
DB_PASSWORD = ""
DB_HOST = ""
DB_PORT = 5432
# port, name, host, allowed hosts
DB_NAME=${DB_NAME:-postgres}
DB_USER=${DB_USER:-postgres}
DB_PASSWORD=${DB_PASSWORD:-postgres}
DB_HOST=${DB_HOST:-db}
DB_PORT=${DB_PORT:-5432}
18 changes: 18 additions & 0 deletions .github/workflows/docker_image_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Use hotosm workflow immage build fors pushes to main or release branches
name: Image Build

on:
push:
branches:
- 'main'
- 'release/*'
- 'dev'

jobs:
pytest:
uses: hotosm/gh-workflows/.github/workflows/test_pytest.yml@main
secrets: inherit
with:
image_name: ghcr.io/${{ github.repository }}
build_target: prod
environment: dev
22 changes: 22 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Use hotosm workflow test_compose for pull requests to main or release branches
name: PyTest

on:
pull_request:
branches:
- 'main'
- 'release/*'
- 'dev'
jobs:
pytest:
uses: hotosm/gh-workflows/.github/workflows/test_compose.yml@main
secrets: inherit
with:
image_name: ghcr.io/${{ github.repository }}/backend
build_dockerfile: Dockerfile
build_target: test
compose_service: web
compose_command: "pytest"
compose_file: "docker-compose.dev.yml"
cache_extra_imgs: |
"docker.io/postgres:16-alpine3.18"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
.env.dev
.env.prod
.env
**/__pycache__/
**/.pytest_cache/
**/.venv/
201 changes: 201 additions & 0 deletions COPYING

Large diffs are not rendered by default.

167 changes: 127 additions & 40 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,58 +1,145 @@
# Use an official Python runtime based on Debian 10 "buster" as a parent image.
FROM python:3.10-slim-buster
ARG PYTHON_IMG_TAG=3.11

# Add user that will be used in the container.
RUN useradd wagtail

# Port used by this container to serve HTTP.
EXPOSE 8000
# Define the base stage
FROM docker.io/python:${PYTHON_IMG_TAG}-slim-bookworm as base
ARG APP_VERSION
ARG COMMIT_REF
ARG PYTHON_IMG_TAG
LABEL org.hotosm.fmtm.app-name="backend" \
org.hotosm.fmtm.app-version="${APP_VERSION}" \
org.hotosm.fmtm.git-commit-ref="${COMMIT_REF:-none}" \
org.hotosm.fmtm.python-img-tag="${PYTHON_IMG_TAG}" \
org.hotosm.fmtm.maintainer="[email protected]" \
org.hotosm.fmtm.api-port="8000"
RUN set -ex \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install \
-y --no-install-recommends "locales" "ca-certificates" \
&& DEBIAN_FRONTEND=noninteractive apt-get upgrade -y \
&& rm -rf /var/lib/apt/lists/* \
&& update-ca-certificates
# Set locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

# Set environment variables.
# 1. Force Python stdout and stderr streams to be unbuffered.
# 2. Set PORT variable that is used by Gunicorn. This should match "EXPOSE"
# command.
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1\
PORT=8000

# Install system packages required by Wagtail and Django.
RUN apt-get update --yes --quiet && apt-get install --yes --quiet --no-install-recommends \
build-essential \
libpq-dev \
libmariadbclient-dev \
libjpeg62-turbo-dev \
zlib1g-dev \
libwebp-dev \
&& rm -rf /var/lib/apt/lists/*
# Extract dependencies using poetry (to requirements.txt)
FROM base as extract-deps
WORKDIR /opt/python
COPY pyproject.toml poetry.lock* /opt/python/
RUN pip install --no-cache-dir --upgrade pip \
&& pip install --no-cache-dir \
poetry==1.7.1 poetry-plugin-export==1.6.0 \
&& poetry config warnings.export false
RUN poetry export --without dev --output requirements.txt
RUN poetry export --only dev --output requirements-dev.txt

# Install pipenv
RUN pip install pipenv

# Install the application server.
RUN pip install "gunicorn==20.0.4"
# Define build stage (install deps)
FROM base as build
RUN set -ex \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install \
-y --no-install-recommends \
"build-essential" \
"gcc" \
"libpq-dev" \
"libmariadb-dev" \
"libjpeg62-turbo-dev" \
"zlib1g-dev" \
"libwebp-dev" \
&& rm -rf /var/lib/apt/lists/*
COPY --from=extract-deps \
/opt/python/requirements.txt /opt/python/
RUN pip install --user --no-warn-script-location \
--no-cache-dir -r /opt/python/requirements.txt

# Copy Pipfile and Pipfile.lock
COPY Pipfile Pipfile.lock ./

# Install the project requirements.
RUN pipenv install --system --deploy

# Define run stage
FROM base as runtime
ARG PYTHON_IMG_TAG
ENV PORT=8000 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PYTHONFAULTHANDLER=1 \
PATH="/home/wagtail/.local/bin:$PATH" \
PYTHONPATH="/app" \
PYTHON_LIB="/home/wagtail/.local/lib/python$PYTHON_IMG_TAG/site-packages" \
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \
CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
# Install non-dev versions of packages (smaller)
RUN set -ex \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install \
-y --no-install-recommends \
"postgresql-client" \
"libmariadb3" \
"libjpeg62-turbo" \
"zlib1g" \
"libwebp-dev" \
&& rm -rf /var/lib/apt/lists/*
# Copy the entrypoint script into the Docker image
COPY --chown=wagtail:wagtail entrypoint.dev.sh /app/entrypoint.dev.sh
# Copy pip dependencies from build stage
COPY --from=build \
/root/.local \
/home/wagtail/.local
# Use /app folder as a directory where the source code is stored.
WORKDIR /app
# Copy project
COPY . /app/
# Add non-root user, permissions
RUN useradd -u 1001 -m -c "hotosm account" -d /home/wagtail -s /bin/false wagtail \
&& chown -R wagtail:wagtail /app /home/wagtail \
&& chmod +x /app/entrypoint.dev.sh
# Change to non-root user
USER wagtail

# Set this directory to be owned by the "wagtail" user. This Wagtail project
# uses SQLite, the folder needs to be owned by the user that
# will be writing to the database file.
RUN chown wagtail:wagtail /app

# Copy the source code of the project into the container.
COPY --chown=wagtail:wagtail . .
# Define test (ci) stage
FROM runtime as test
USER root
ARG PYTHON_IMG_TAG
COPY --from=extract-deps \
/opt/python/requirements-dev.txt /opt/python/
# Copy packages from user to root dirs (run ci as root)
# && install dev dependencies (pytest)
RUN mv /home/wagtail/.local/bin/* /usr/local/bin/ \
&& mv /home/wagtail/.local/lib/python${PYTHON_IMG_TAG}/site-packages/* \
/usr/local/lib/python${PYTHON_IMG_TAG}/site-packages/ \
&& pip install --upgrade --no-warn-script-location \
--no-cache-dir -r \
/opt/python/requirements-dev.txt \
&& rm -r /opt/python \
# Pre-compile packages to .pyc (init speed gains)
&& python -c "import compileall; compileall.compile_path(maxlevels=10, quiet=1)"
CMD [ "pytest" ]

# Use user "wagtail" to run the build commands below and the server itself.
USER wagtail

# Collect static files.
RUN python manage.py collectstatic --noinput --clear
# Define debug (development) stage
FROM runtime as debug
# Add Healthcheck
HEALTHCHECK --start-period=10s --interval=5s --retries=20 --timeout=5s \
CMD curl --fail http://localhost:8000 || exit 1
# Use the entrypoint script as the Docker entrypoint
ENTRYPOINT ["/app/entrypoint.dev.sh"]
CMD ["./wait-for-it.sh", "db:5432", "--", \
"python", "manage.py", "runserver", "0.0.0.0:8000"]


# Define prod stage
FROM runtime as prod
# Add Healthcheck
HEALTHCHECK --start-period=10s --interval=5s --retries=20 --timeout=5s \
CMD curl --fail http://localhost:8000 || exit 1
# Pre-compile packages to .pyc (init speed gains)
RUN python -c "import compileall; compileall.compile_path(maxlevels=10, quiet=1)" \
# Collect static files
&& python manage.py collectstatic --noinput --clear
# Runtime command that executes when "docker run" is called, it does the
# following:
# 1. Migrate the database.
Expand Down
14 changes: 14 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Copyright (C) 2023 Humanitarian OpenStreetMap Team

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.PHONY: build-dev build-prod test up-dev up-prod down-dev down-prod

build-dev:
@docker compose -f docker-compose.dev.yml build
@docker compose -f docker-compose.dev.yml up -d

build-prod:
@docker compose -f docker-compose.prod.yml build
@docker compose -f docker-compose.prod.yml up -d

test:
@docker build --target test -t myproject:test -f Dockerfile .
@docker run --rm myproject:test
@docker rmi myproject:test

up-dev:
@docker compose -f docker-compose.dev.yml up -d

up-prod:
@docker compose -f docker-compose.prod.yml up

down-dev:
@docker compose -f docker-compose.dev.yml down

down-prod:
@docker compose -f docker-compose.prod.yml down

refresh-db:
@if [ -n "$(shell docker volume ls -q)" ]; then docker volume rm $(shell docker volume ls -q); fi
15 changes: 0 additions & 15 deletions Pipfile

This file was deleted.

Loading