Skip to content

Commit

Permalink
Merge pull request #63 from kjsanger/feature/docker
Browse files Browse the repository at this point in the history
Add a development Dockerfile
  • Loading branch information
nerdstrike authored Jun 26, 2024
2 parents afc56b1 + ffbb100 commit 261ae7e
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 0 deletions.
99 changes: 99 additions & 0 deletions docker/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@

ARG BASE_IMAGE=python:3.10-slim
FROM $BASE_IMAGE as builder

ARG DEBIAN_FRONTEND="noninteractive"

RUN apt-get update && \
apt-get install -q -y --no-install-recommends \
build-essential \
gcc \
libsqlite3-dev \
unattended-upgrades && \
unattended-upgrade -v

WORKDIR /app

COPY .. .

RUN python -m venv /app && \
. ./bin/activate && \
pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir .


FROM $BASE_IMAGE

ARG DEBIAN_FRONTEND

RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -q -y --no-install-recommends \
libsqlite3-0 \
postgresql \
sudo \
tini \
locales && \
locale-gen en_GB en_GB.UTF-8 && \
localedef -i en_GB -c -f UTF-8 -A /usr/share/locale/locale.alias en_GB.UTF-8

RUN apt-get install -q -y --no-install-recommends \
unattended-upgrades && \
unattended-upgrade -v && \
apt-get remove -q -y unattended-upgrades && \
apt-get autoremove -q -y && \
apt-get clean -q -y && \
rm -rf /var/lib/apt/lists/*

ENV LANG=en_GB.UTF-8 \
LANGUAGE=en_GB \
LC_ALL=en_GB.UTF-8 \
TZ="Etc/UTC"

ARG APP_USER=appuser
ARG APP_UID=1000
ARG APP_GID=$APP_UID

WORKDIR /app

RUN groupadd --gid $APP_GID $APP_USER && \
useradd --uid $APP_UID --gid $APP_GID --shell /bin/bash --create-home $APP_USER

COPY --from=builder --chown=$APP_USER:$APP_GID /app /app

ARG DB_HOST=localhost
ARG DB_PORT=5432
ARG DB_SCHEMA=porch_dev
ARG DB_NAME=porch_dev_db
ARG DB_USER=porch_admin
ARG DB_PASS=porch
ARG URL_SLUG="$DB_USER:$DB_PASS@$DB_HOST:$DB_PORT/$DB_NAME"

ENV DB_HOST=$DB_HOST \
DB_PORT=$DB_PORT \
DB_SCHEMA=$DB_SCHEMA \
DB_NAME=$DB_NAME \
DB_USER=$DB_USER \
DB_PASS=$DB_PASS \
DB_URL="postgresql+psycopg2://$URL_SLUG"

RUN service postgresql start && \
/app/docker/scripts/create_database.sh && \
/app/docker/scripts/configure_database_service.sh && \
. /app/bin/activate && \
/app/scripts/deploy_schema.py && \
/app/docker/scripts/insert_admin_token.sh && \
service postgresql stop

USER $APP_USER

ARG PORT=8081

ENV DB_URL="postgresql+asyncpg://$URL_SLUG" \
PORT=${PORT}

EXPOSE ${PORT}

ENTRYPOINT ["/usr/bin/tini", "--"]

CMD ["/app/docker/scripts/entrypoint.sh"]
19 changes: 19 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Development Dockerfile

The Dockerfile and scripts in this directory may be use to create a development image
that hosts both the PostgreSQL database and the npg_porch server.

The application is populated with a hard-coded administrator user, password and
administration token and is configured log to STDERR and STDOUT.

To create an image using the Dockerfile, run the following command from the root of the
repository:

```bash
docker build --rm -f docker/Dockerfile.dev -t npg_porch_dev .
```

The Dockerfile supports a number of arguments that can be passed to the `docker build`
command to configure most aspects of the application, including user names, passwords,
database names and ports. However, the default values should be suitable for most
needs.
51 changes: 51 additions & 0 deletions docker/logging.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"version": 1,
"formatters": {
"default": {
"()": "uvicorn.logging.DefaultFormatter",
"fmt": "%(levelprefix)s %(message)s",
"use_colors": null
},
"access": {
"()": "uvicorn.logging.AccessFormatter",
"fmt": "%(levelprefix)s %(client_addr)s - \"%(request_line)s\" %(status_code)s"
}
},
"handlers": {
"stderr": {
"formatter": "default",
"class": "logging.StreamHandler",
"stream": "ext://sys.stderr"
},
"stdout": {
"formatter": "default",
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout"
},
"access": {
"formatter": "access",
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout"
}
},
"loggers": {
"uvicorn": {
"handlers": ["access"],
"level": "INFO",
"propagate": false
},
"uvicorn.error": {
"handlers": ["stderr"],
"level": "DEBUG",
"propagate": false
},
"fastapi": {
"handlers": ["stderr"],
"level": "INFO"
}
},
"root": {
"handlers": ["stdout"],
"level": "DEBUG"
}
}
12 changes: 12 additions & 0 deletions docker/scripts/configure_database_service.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

set -eo pipefail
set -x

APP_USER=${APP_USER:? The APP_USER environment variable must be set}

cat > "/etc/sudoers.d/$APP_USER" << EOF
$APP_USER ALL= NOPASSWD: /usr/sbin/service postgresql start
$APP_USER ALL= NOPASSWD: /usr/sbin/service postgresql restart
$APP_USER ALL= NOPASSWD: /usr/sbin/service postgresql stop
EOF
30 changes: 30 additions & 0 deletions docker/scripts/create_database.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash

set -eo pipefail
set -x

pg_isready --quiet || {
echo "PostgreSQL is not ready" >&2
exit 1
}

DB_SCHEMA=${DB_SCHEMA:? The DB_SCHEMA environment variable must be set}
DB_NAME=${DB_NAME:? The DB_NAME environment variable must be set}
DB_USER=${DB_USER:? The DB_USER environment variable must be set}
DB_PASS=${DB_PASS:? The DB_PASS environment variable must be set}

sudo -u postgres createuser -D -R -S ${DB_USER}
sudo -u postgres createdb -O ${DB_USER} ${DB_NAME}

sudo -u postgres psql -d ${DB_NAME} << EOF
ALTER USER ${DB_USER} WITH PASSWORD '${DB_PASS}';
CREATE SCHEMA ${DB_SCHEMA};
SET search_path TO ${DB_SCHEMA}, public;
GRANT ALL PRIVILEGES ON SCHEMA ${DB_SCHEMA} TO ${DB_USER};
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA ${DB_SCHEMA} TO ${DB_USER};
GRANT USAGE ON ALL SEQUENCES IN SCHEMA ${DB_SCHEMA} TO ${DB_USER};
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA ${DB_SCHEMA} TO ${DB_USER};
EOF
16 changes: 16 additions & 0 deletions docker/scripts/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

set -eo pipefail

sudo service postgresql start

pg_isready --quiet --timeout=30 || {
echo "PostgreSQL is not ready" >&2
exit 1
}

PORT=${PORT:? The PORT environment variable must be set}

source /app/bin/activate

uvicorn npg_porch.server:app --host 0.0.0.0 --port ${PORT} --reload --log-config /app/docker/logging.json
18 changes: 18 additions & 0 deletions docker/scripts/insert_admin_token.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

set -eo pipefail
set -x

pg_isready --quiet || {
echo "PostgreSQL is not ready" >&2
exit 1
}

DB_SCHEMA=${DB_SCHEMA:? The DB_SCHEMA environment variable must be set}
DB_NAME=${DB_NAME:? The DB_NAME environment variable must be set}

ADMIN_TOKEN=${ADMIN_TOKEN:="00000000000000000000000000000000"}

sudo -u postgres psql -d ${DB_NAME} << EOF
INSERT INTO ${DB_SCHEMA}."token" (token, description, date_issued) VALUES ('${ADMIN_TOKEN}', 'Admin token', NOW());
EOF
2 changes: 2 additions & 0 deletions scripts/deploy_schema.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env python

# Replace with Alembic in due course

import os
Expand Down

0 comments on commit 261ae7e

Please sign in to comment.