diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d00866..938b605 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,5 +20,8 @@ jobs: - name: Build docker images run: docker compose build + - name: Run containers + run: docker compose up -d + - name: Run PyTest - run: docker compose run test + run: docker exec mapdb-django-dev pytest diff --git a/README.md b/README.md index 9f68d2f..65c9cb1 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Follow this guide to set up the api locally for development. > [!note] > By default, we are using Docker for the sake of simplicity. If you want to run the API natively, you can check out the section [Native Guide](#native-guide). -- Docker with compose +- Docker - An IDE (PyCharm strongly recommended) ### Set up environment variables @@ -41,11 +41,47 @@ You can copy `example.env` to `.env` and fill in the required values. Run the following command to start the API: ```bash -docker compose up nginx-server -d +docker compose up -d ``` > Now you can access the API at `http://localhost` +### Running the tests + +Once the api is started you can run the tests using the following command. + +Run tests +``` +docker exec -it mapdb-django-dev pytest +``` + +## Production + +> This section is still a WIP... + +Follow this guide to set up the app for production. + +### Prerequisites + +- Docker + +### Set up environment variables + +You can copy `example.env` to `.env` and fill in the required values. + +- Set `POSTGRES_PASSWORD` to a secure password. +- Set `SECRET_KEY` to a secure secret key. You can use `from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())` in a python shell to generate it. +- You MUST set `DEBUG` to `0` +- You MUST set `RUN_ENVIRONMENT` to `production` + +### Running the API + +Run the following command to start the API: + +```bash +docker compose -f docker-compose.prod.yml up -d +``` + ## Native Guide You should use docker compose, but here are the native OS instructions in case you don't want to. diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..68222e3 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,44 @@ +services: + db: + container_name: mapdb-postgres + image: postgres + volumes: + - ${POSTGRES_DATA_DIR}:/var/lib/postgresql/data + environment: + - POSTGRES_DB=${POSTGRES_DB} + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + env_file: + - .env + ports: + - "127.0.0.1:${POSTGRES_PORT}:${POSTGRES_PORT}" + command: -p ${POSTGRES_PORT} + + django: + container_name: mapdb-django + build: + context: . + dockerfile: docker/Dockerfile + target: prod + volumes: + - ${HOST_MEDIA_ROOT}:/data/cncnet_silo # django will save user-uploaded files here. MEDIA_ROOT + - ${HOST_STATIC_ROOT}:/data/cncnet_static # django will gather static files here. STATIC_ROOT + ports: + - "8000:8000" + env_file: + - .env + depends_on: + - db + + nginx-server: + # nginx proxies requests to django via gunicorn. + container_name: mapdb-nginx + image: nginx:latest + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + - ${HOST_STATIC_ROOT}:/usr/share/nginx/html/static # website static assets. + - ${HOST_MEDIA_ROOT}:/usr/share/nginx/html/silo # website user-uploaded files. + ports: + - "80:80" + depends_on: + - django diff --git a/docker-compose.yml b/docker-compose.yml index d7f52b0..52f55dd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,6 @@ services: db: + container_name: mapdb-postgres-dev image: postgres volumes: - ${POSTGRES_DATA_DIR}:/var/lib/postgresql/data @@ -14,8 +15,11 @@ services: command: -p ${POSTGRES_PORT} django: - # Won't serve files on its own. Launch nginx-server to run the whoe app. - build: . + container_name: mapdb-django-dev + build: + context: . + dockerfile: docker/Dockerfile + target: dev volumes: - .:/cncnet-map-api - ${HOST_MEDIA_ROOT}:/data/cncnet_silo # django will save user-uploaded files here. MEDIA_ROOT @@ -28,46 +32,14 @@ services: - db nginx-server: - # This is the prod server service. - # `docker compose up nginx -d` will run the whole app. # nginx proxies requests to django via gunicorn. + container_name: mapdb-nginx-dev image: nginx:latest volumes: - - ./nginx.conf:/etc/nginx/nginx.conf:ro + - ./docker/nginx.conf:/etc/nginx/nginx.conf:ro - ${HOST_STATIC_ROOT}:/usr/share/nginx/html/static # website static assets. - ${HOST_MEDIA_ROOT}:/usr/share/nginx/html/silo # website user-uploaded files. ports: - "80:80" depends_on: - django - - test: - build: - context: ./ - dockerfile: test.DockerFile - volumes: - - .:/cncnet-map-api - env_file: - - .env - environment: - POSTGRES_TEST_HOST: db # Necessary to connect to docker db. Overrides the .env setting. - depends_on: - - db - command: - - pytest - - windows-dev: - # Use this for windows. The LZO libraries are annoying to deal with without using docker. - # Chairman Bing of Massivesoft strikes again. - build: - context: ./ - dockerfile: test.DockerFile - volumes: - - .:/cncnet-map-api - - ./data/tmp:/tmp/pytest-of-root # For inspecting files during pytests - env_file: - - .env - environment: - POSTGRES_TEST_HOST: db # Necessary to connect to docker db. Overrides the .env setting. - depends_on: - - db diff --git a/Dockerfile b/docker/Dockerfile similarity index 55% rename from Dockerfile rename to docker/Dockerfile index 2adbdc1..3b80d99 100644 --- a/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12-bookworm as base +FROM python:3.12-bookworm AS base ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 @@ -12,11 +12,22 @@ COPY requirements.txt /cncnet-map-api COPY requirements-dev.txt /cncnet-map-api COPY web_entry_point.sh /cncnet-map-api -RUN apt-get update && apt-get install -y liblzo2-dev # Compression library used by westwood. -RUN apt-get install libmagic1 # File type checking. +# liblzo2 is a compression library used by westwood. +# libmagic1 is used for detecting file mime types by analyzing the file contents. +RUN apt-get update && apt-get install -y liblzo2-dev libmagic1 RUN pip install --upgrade pip +RUN chmod +x /cncnet-map-api/web_entry_point.sh + +FROM base AS dev # The cflags are needed to build the lzo library on Apple silicon. RUN CFLAGS=-I$(brew --prefix)/include LDFLAGS=-L$(brew --prefix)/lib pip install -r ./requirements-dev.txt +ENTRYPOINT "/cncnet-map-api/web_entry_point.sh" + +FROM base AS prod +# The cflags are needed to build the lzo library on Apple silicon. +RUN CFLAGS=-I$(brew --prefix)/include LDFLAGS=-L$(brew --prefix)/lib pip install -r ./requirements.txt + +COPY . /cncnet-map-api -RUN chmod +x /cncnet-map-api/web_entry_point.sh ENTRYPOINT "/cncnet-map-api/web_entry_point.sh" + diff --git a/nginx.conf b/docker/nginx.conf similarity index 100% rename from nginx.conf rename to docker/nginx.conf diff --git a/example.env b/example.env index 6d2a2ea..9850b0f 100644 --- a/example.env +++ b/example.env @@ -14,7 +14,7 @@ POSTGRES_DATA_DIR=./data/db/ # In docker the host will always be DB, but when run locally it will probably be local host. # The reason this is separate from production host is because putting PyCharm breakpoints in docker has issues # and pytests often need to be run locally to have breakpoints work. -POSTGRES_TEST_HOST=localhost +POSTGRES_TEST_HOST=db # Port for postgres POSTGRES_PORT=5432 diff --git a/test.DockerFile b/test.DockerFile deleted file mode 100644 index 65adc14..0000000 --- a/test.DockerFile +++ /dev/null @@ -1,18 +0,0 @@ -# Dockerfile to use for running the tests via docker-compose run test -FROM python:3.12-bookworm as base - -ENV PYTHONDONTWRITEBYTECODE=1 -ENV PYTHONUNBUFFERED=1 -WORKDIR /cncnet-map-api - -# This is just here to crash the build if you don't make a .env file. -COPY .env /cncnet-map-api/ - -# Copy files needed for build -COPY requirements.txt /cncnet-map-api -COPY requirements-dev.txt /cncnet-map-api -COPY web_entry_point.sh /cncnet-map-api - -RUN apt-get update && apt-get install -y liblzo2-dev -RUN pip install --upgrade pip -RUN CFLAGS=-I$(brew --prefix)/include LDFLAGS=-L$(brew --prefix)/lib pip install -r requirements-dev.txt