Skip to content

Commit

Permalink
adds docker support for integration testing and running containerized…
Browse files Browse the repository at this point in the history
… service (#75)

resolves #73

adds:

- Dockerfile.build: This is the base multi-stage image.
- Dockerfile: Main image to run the service using docker compose.
- Dockerfile.test-integration: For running integration tests.

<!-- Generated by sourcery-ai[bot]: start summary -->

## Summary by Sourcery

Add Docker support for integration testing and running the service in a
containerized environment. Update documentation to guide developers on
setting up and using Docker for local testing and service emulation.
Introduce Dockerfiles for building base, main, and integration test
images, and add a Docker Compose configuration for service deployment.

New Features:
- Introduce Docker support for integration testing and running the
service in a containerized environment using Docker Compose.

Enhancements:
- Update CONTRIBUTING.md and README.md to include instructions for
setting up and running the containerized application, enhancing the
documentation for developers.

Build:
- Add Dockerfile.build for creating a base multi-stage image, Dockerfile
for the main service image, and Dockerfile.test-integration for
integration testing.

Deployment:
- Add docker-compose.yml to define the containerized service setup,
including shared configuration for ports, volumes, and logging.

Documentation:
- Enhance user-facing documentation in CONTRIBUTING.md and README.md to
guide developers on using Docker for local integration testing and
service emulation.

<!-- Generated by sourcery-ai[bot]: end summary -->
  • Loading branch information
codecakes authored Sep 20, 2024
1 parent 2712802 commit 6f3d6ae
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 8 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/stage_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ jobs:

- name: Run Pre-commit
run: |
if [ -f "poetry.lock" ]; then echo "running poetry lock" && poetry lock --no-update; fi;
poetry install --no-root --all-extras
poetry run pre-commit run --all-files
poetry run pre-commit run --all-files;
43 changes: 39 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Change directories into the newly cloned project-healthcare folder:
`cd project-healthcare`

## Setting Up Your Development Environment

When you are developing features or running unit-tests, the local setup prescribed here without container setup will work fine. However, it is recommended to setup the containers as well for local integration testing and running the service in a container to emulate staging or production environment.

### - Install Dependencies:

#### Set Up the Development Environment
Expand All @@ -37,6 +40,42 @@ Use this command to set up automatic checks that will help catch errors in your

Set up your preferred code editor or IDE for a smooth development experience. Consider installing extensions or plugins for syntax highlighting, code completion, and debugging specific to the programming languages used in the project.

### - Running & Testing Containerized Setup:

`Makefile` contains actual script for setup. `docker` is replaceable with `podman` as a drop-in if you use Podman.

All images use the base image from `Dockerfile.build` for multi-stage builds.

#### Set Up Container Images

1. Setup base image:

```bash
# Build the base Docker image for the project
make docker-build
```

2. Setup integration test image:

```bash
# Build the base Docker image for integration test
make docker-integration
```

#### Running Containerized Application

For local smoke testing and runs:

```bash
make docker-run-server
```

For integration, api or end to end testing:

```bash
make docker-test-integration
```

## Reporting Bugs Or Issues 🐞

Before reporting a bug, please determine the type of issue you're encountering:
Expand Down Expand Up @@ -180,7 +219,3 @@ We appreciate your contributions to Project-Healthcare! Your efforts help us mak
Thank you! ❤️ ❤️
— The Project-Healthcare Team
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Use the base image for Python setup
# Reuse the stage from Dockerfile.build
FROM xcov19-setup AS run

USER nonroot:nonroot

# Set the start command
ARG START_CMD="make run"
ENV START_CMD=${START_CMD}
RUN if [ -z "${START_CMD}" ]; then echo "Unable to detect a container start command" && exit 1; fi
CMD ${START_CMD}
120 changes: 120 additions & 0 deletions Dockerfile.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Use the base image specified
ARG VERSION=3.12.6
ARG BUILDER=docker.io/library/python
FROM ${BUILDER}:${VERSION}-slim AS python-base

# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
curl \
git \
libbz2-dev \
libffi-dev \
libgdal-dev \
libgeos-dev \
liblzma-dev \
libncursesw5-dev \
libproj-dev \
libreadline-dev \
libsqlite3-dev \
libsqlite3-mod-spatialite \
libssl-dev \
libxml2-dev \
libxmlsec1-dev \
pkg-config \
tk-dev \
unzip \
uuid-dev \
wget \
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*

# Update CA certificates
RUN update-ca-certificates 2>/dev/null || true

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# Compile SQLite with loadable extension support
ENV SQLITE_VERSION=3460100
RUN mkdir -p /build && cd /build && \
wget --max-redirect=0 --secure-protocol=TLSv1_2 https://www.sqlite.org/2024/sqlite-amalgamation-${SQLITE_VERSION}.zip && \
unzip sqlite-amalgamation-${SQLITE_VERSION}.zip && \
rm sqlite-amalgamation-${SQLITE_VERSION}.zip && \
cd sqlite-amalgamation-${SQLITE_VERSION} && \
gcc -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_JSON1 \
-DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
-DHAVE_READLINE -DSQLITE_ENABLE_DBSTAT_VTAB \
shell.c sqlite3.c -ldl -lm -lreadline -lncurses -o sqlite3 && \
rm -rf /build


# Recompile Python to link against the custom SQLite
ENV PYTHON_VERSION=3.12.6
RUN mkdir -p /build && cd /build && \
wget --max-redirect=0 --secure-protocol=TLSv1_2 -q https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz && \
tar xzf Python-${PYTHON_VERSION}.tgz && \
cd Python-${PYTHON_VERSION} && \
./configure \
--enable-optimizations \
--with-ensurepip=install \
--enable-loadable-sqlite-extensions \
LDFLAGS="-L/usr/local/lib" \
CPPFLAGS="-I/usr/local/include" \
PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" && \
make -j"$(nproc)" && \
make altinstall && \
rm -rf /build

# Update alternatives to point to the new Python
RUN ln -sf /usr/local/bin/python${PYTHON_VERSION%.*} /usr/local/bin/python3
RUN ln -sf /usr/local/bin/pip${PYTHON_VERSION%.*} /usr/local/bin/pip3

# Use the base image for Python setup
# Reuse the stage from Dockerfile.build
FROM python-base AS xcov19-setup

# Set the working directory
WORKDIR /app
# Create nonroot user and group
RUN addgroup --system nonroot && adduser --system --ingroup nonroot nonroot

# Change ownership of /app and /var/cache
RUN chown -R nonroot:nonroot /app
RUN mkdir -p /var/cache
RUN chown -R nonroot:nonroot /var/cache

# Copy the application code
COPY --chown=nonroot:nonroot --chmod=555 xcov19 xcov19/
COPY --chown=nonroot:nonroot --chmod=555 Makefile .
COPY --chown=nonroot:nonroot --chmod=555 pyproject.toml .
COPY --chown=nonroot:nonroot --chmod=555 poetry.lock .
COPY --chown=nonroot:nonroot --chmod=555 *.sh .
COPY --chown=nonroot:nonroot --chmod=555 LICENSE .

ENV POETRY_NO_INTERACTION=1
ENV POETRY_VIRTUALENVS_CREATE=false
ENV POETRY_CACHE_DIR='/var/cache/pypoetry'
ENV POETRY_HOME='/usr/local'

# Install Poetry using the recompiled Python
RUN curl --proto "=https" --tlsv1.2 -sSf -L https://install.python-poetry.org | python3 -

# Change ownership of Poetry's cache and configuration directories
RUN mkdir -p /var/cache/pypoetry && chown -R nonroot:nonroot /var/cache/pypoetry
RUN chown -R nonroot:nonroot /usr/local/ && chmod -R 755 /usr/local/

# Switch to nonroot user
USER nonroot:nonroot


# Install project dependencies
ARG INSTALL_CMD="poetry install --only main --no-root --no-ansi"
RUN if [ -z "${INSTALL_CMD}" ]; then echo "Unable to start poetry install command" && exit 1; fi
RUN if [ -f "poetry.lock" ]; then \
echo "poetry lock exists. updating" && \
chmod 755 poetry.lock && poetry lock --no-update; fi;
RUN ${INSTALL_CMD}
16 changes: 16 additions & 0 deletions Dockerfile.test-integration
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Use the base image for Python setup
# Reuse the stage from Dockerfile.build
FROM xcov19-setup AS test-integration

# Switch to nonroot user
USER nonroot:nonroot

ARG INSTALL_CMD="poetry install --no-root --no-ansi --extras=test"
RUN if [ -z "${INSTALL_CMD}" ]; then echo "Unable to start poetry install command" && exit 1; fi
RUN if [ -f "poetry.lock" ]; then echo "poetry lock exists. updating" && poetry lock --no-update; fi;
RUN ${INSTALL_CMD}

ARG START_CMD="make test-integration"
ENV START_CMD=${START_CMD}
RUN if [ -z "${START_CMD}" ]; then echo "Unable to detect a container start command" && exit 1; fi
CMD ${START_CMD}
17 changes: 16 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
XCOV19_SETUP_IMAGE := xcov19-setup
XCOV19_TEST_INTEGRATION_SETUP_IMAGE := xcov19-integration-test

check:
@bash check.sh

Expand All @@ -17,4 +20,16 @@ test-integration:
APP_ENV=test APP_DB_ENGINE_URL="sqlite+aiosqlite://" pytest -s xcov19/tests/ -m "integration"

todos:
@grep -rn "TODO:" xcov19/ --exclude-dir=node_modules --include="*.py"
@grep -rn "TODO:" xcov19/ --exclude-dir=node_modules --include="*.py"

docker-build:
docker build --load -f Dockerfile.build -t $(XCOV19_SETUP_IMAGE) .

docker-integration:
docker build --load -f Dockerfile.test-integration -t $(XCOV19_TEST_INTEGRATION_SETUP_IMAGE) .

docker-run-server:
docker compose -f docker-compose.yml up --build

docker-test-integration:
make docker-integration && docker run -it -f Dockerfile.test-integration
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Released under [LGPL-2.1](/LICENSE) by [@Xcov19](https://github.com/Xcov19).
# Project Healthcare (xcov19)

Project Healthcare, from hereon called the brokering service, is a set of upstream OpenAPI specification to extend any patient facing user interface looking to integrate to location-aware consultation and diagnostics facilities near them by:

1. Exposing a diagnosis API to capture patient symptoms.
2. Exposing geolocation API to caputure patient's location and offer nearby facilities to take action on based on their diagnosis and location.

Expand All @@ -42,6 +43,7 @@ web framework to start Web APIs, the project structure adheres blacksheep's doma
domain driven design philosophy using ports and adapters pattern so expect slight shift towards domain models and services structure.

The specification follows a sandwich service model i.e. it requires one or more upstream producer services and one downstream consumer service as follows:

1. The patient facing application, known from hereon as the downstream consumer service, calls the diagnosis and geolocation API.
2. The brokering service stores transient diagnosis request and enqueues them to upstream provider service that should return records of facilities and their specialties based on the diagnosis.
3. The brokering service returns the records of matching facilities to the downstream consumer service.
Expand Down
17 changes: 17 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: "3"

x-shared-config: &shared-config
ports:
- "${PORT:-44777}:44777"
restart: always
logging:
options:
max-size: 0.25g
max-file: 2

services:
xcov19-app:
<<: *shared-config
build:
context: .
dockerfile: Dockerfile
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ sqlalchemy = {version="^2.0.34", markers = "sys_platform != 'win32'", extras = [
alembic = "^1.13.2"
aiosqlite = "^0.20.0"
sqlmodel = {version="^0.0.22"}
rich = {version = "^13.8.0"}

ruff = { version = "^0.6.3", optional = true }
mypy = { version = "^1.11.2", optional = true }
blacksheep-cli = { version = "^0.0.4", optional = true }
rich = { version = "^13.8.0", optional = true }
pyright = { version = "^1.1.379", optional = true }
pre-commit = { version="^3.7.1", optional = true }
pytest-asyncio = { version = "^0.24.0", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion run.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash

APP_ENV=dev APP_DB_ENGINE_URL="sqlite+aiosqlite:///xcov19.db" poetry run python3 -m xcov19.dev
if [ -f "xcov19.db" ]; then rm xcov19.db; fi; APP_ENV=dev APP_DB_ENGINE_URL="sqlite+aiosqlite:///xcov19.db" poetry run python3 -m xcov19.dev

0 comments on commit 6f3d6ae

Please sign in to comment.