🔧 containers: Replace Docker with Podman and UBI-based Containerfile
Replace the broken Docker setup (Python 3.6 Alpine, `pipenv`, hardcoded credentials) with a modern Podman-based development environment using Red Hat Universal Base Images for OpenShift compatibility. `Containerfile` (replaces `Dockerfile`): - Multi-stage build: builder stage installs Poetry and dependencies, runtime stage copies only the installed packages for a smaller image - Base image: UBI 9 Python 3.12 (OpenShift-certified) - Runs as non-root `USER 1001` (required by OpenShift SCC) - Gunicorn as the application server instead of Django's runserver - No longer calls `generate_client_secrets.sh` during build `podman-compose.yml` (replaces `docker-compose.yml`): - PostgreSQL 17, Redis 7, RabbitMQ 3 with health checks - `depends_on` with `service_healthy` conditions instead of links - Named volume (`pgdata`) for PostgreSQL persistence - SELinux `:z` labels on bind mounts for Fedora hosts - Gunicorn with `--reload` for development hot-reload Also adds: - `.env.example` — template for local development secrets - `.containerignore` — excludes .git, secrets, and build artifacts from the container image Closes #222. Closes #265. Assisted-by: Claude Opus 4.6 (1M context) Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
This commit is contained in:
parent
500b0d7d94
commit
565f7757bf
7 changed files with 128 additions and 75 deletions
15
.containerignore
Normal file
15
.containerignore
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
.git
|
||||
.forgejo
|
||||
.claude
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
*.sqlite3
|
||||
htmlcov/
|
||||
.coverage
|
||||
docs/_build/
|
||||
static/
|
||||
media/
|
||||
selenium-screenshots/
|
||||
whoosh_index/
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
**/*.pyc
|
||||
**/__pycache__
|
||||
16
.env.example
Normal file
16
.env.example
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Copy this file to .env and fill in the values.
|
||||
# Used by podman-compose for local development.
|
||||
|
||||
# OIDC credentials (register at Fedora OIDC provider)
|
||||
OIDC_RP_CLIENT_ID=
|
||||
OIDC_RP_CLIENT_SECRET=
|
||||
|
||||
# FAS admin account for username lookups
|
||||
ADMIN_USERNAME=
|
||||
ADMIN_PASSWORD=
|
||||
|
||||
# Django secret key (generate with: python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())")
|
||||
SECRET_KEY=only-for-development
|
||||
|
||||
# Redis URL for cache (Celery uses its own config in settings)
|
||||
REDIS_URL=redis://redis:6379/1
|
||||
30
Containerfile
Normal file
30
Containerfile
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Stage 1: Install dependencies in a temporary builder image.
|
||||
# This stage pulls in Poetry, compilers, and build tools that are
|
||||
# needed to install Python packages but not needed at runtime.
|
||||
FROM registry.access.redhat.com/ubi9/python-312:latest AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY pyproject.toml poetry.lock* ./
|
||||
RUN pip install --no-cache-dir poetry \
|
||||
&& poetry config virtualenvs.create false \
|
||||
&& poetry install --without dev,docs --no-interaction --no-ansi
|
||||
|
||||
# Stage 2: Create the final runtime image.
|
||||
# Starts from a clean base and copies only the installed packages
|
||||
# from the builder, producing a smaller image without build tools.
|
||||
FROM registry.access.redhat.com/ubi9/python-312:latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /opt/app-root /opt/app-root
|
||||
COPY . /app
|
||||
|
||||
RUN python manage.py collectstatic --noinput 2>/dev/null || true
|
||||
|
||||
# Run as non-root user (required by OpenShift security context constraints)
|
||||
USER 1001
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["gunicorn", "happinesspackets.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]
|
||||
33
Dockerfile
33
Dockerfile
|
|
@ -1,33 +0,0 @@
|
|||
# Issue with celery=4.2.1 with Py3.7 hence Py3.6.8 used
|
||||
FROM python:3.6.8-alpine
|
||||
|
||||
ENV DJANGO_SETTINGS_MODULE=happinesspackets.settings.dev
|
||||
ENV FEDORA_MESSAGING_CONF=/app/config.toml
|
||||
|
||||
# Set current working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Install required system packages
|
||||
RUN apk add --update --no-cache \
|
||||
build-base \
|
||||
bash \
|
||||
curl \
|
||||
readline \
|
||||
libffi-dev \
|
||||
ncurses-dev \
|
||||
python3-dev \
|
||||
postgresql-dev
|
||||
|
||||
# Copy project files into container
|
||||
COPY . /app
|
||||
|
||||
# Check if client_secrets.json is present, and generate if not
|
||||
RUN ./generate_client_secrets.sh
|
||||
|
||||
# Install required Python packages
|
||||
RUN pip install pipenv \
|
||||
&& pipenv install --system --deploy --dev
|
||||
|
||||
# Expose Django port
|
||||
EXPOSE 8000
|
||||
CMD [ "./manage.py", "collectstatic", "--noinput" ]
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
version: "3"
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
restart: always
|
||||
command: bash -c "python manage.py migrate --noinput && python manage.py rebuild_index --noinput && python manage.py runserver 0.0.0.0:8000"
|
||||
volumes:
|
||||
- ./templates:/app/templates:z
|
||||
- ./assets:/app/assets:z
|
||||
- ./happinesspackets:/app/happinesspackets:z
|
||||
ports:
|
||||
- "8000:8000"
|
||||
links:
|
||||
- db
|
||||
- redis
|
||||
- rabbitmq
|
||||
rabbitmq:
|
||||
image: rabbitmq:alpine
|
||||
ports:
|
||||
- "5672:5672"
|
||||
environment:
|
||||
RABBITMQ_DEFAULT_PASS: pass
|
||||
RABBITMQ_DEFAULT_USER: user
|
||||
RABBITMQ_DEFAULT_VHOST: vhost
|
||||
redis:
|
||||
image: redis:alpine
|
||||
ports:
|
||||
- "6379:6379"
|
||||
celery:
|
||||
build: .
|
||||
command: celery worker -A happinesspackets -l info
|
||||
links:
|
||||
- db
|
||||
- redis
|
||||
# ports:
|
||||
# - "587:587"
|
||||
db:
|
||||
image: postgres:10-alpine
|
||||
environment:
|
||||
POSTGRES_PASSWORD: example
|
||||
67
podman-compose.yml
Normal file
67
podman-compose.yml
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
version: "3"
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
containerfile: Containerfile
|
||||
environment:
|
||||
DJANGO_SETTINGS_MODULE: happinesspackets.settings.dev
|
||||
FEDORA_MESSAGING_CONF: /app/config.toml
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./happinesspackets:/app/happinesspackets:z
|
||||
- ./templates:/app/templates:z
|
||||
- ./assets:/app/assets:z
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
command: >
|
||||
bash -c "python manage.py migrate --noinput &&
|
||||
gunicorn happinesspackets.wsgi:application --bind 0.0.0.0:8000 --reload"
|
||||
|
||||
db:
|
||||
image: docker.io/postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_PASSWORD: example
|
||||
POSTGRES_DB: postgres
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready", "-U", "postgres"]
|
||||
interval: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: docker.io/redis:7-alpine
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
retries: 5
|
||||
|
||||
celery:
|
||||
build:
|
||||
context: .
|
||||
containerfile: Containerfile
|
||||
environment:
|
||||
DJANGO_SETTINGS_MODULE: happinesspackets.settings.dev
|
||||
command: celery -A happinesspackets worker -l info
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
|
||||
rabbitmq:
|
||||
image: docker.io/rabbitmq:3-management-alpine
|
||||
environment:
|
||||
RABBITMQ_DEFAULT_USER: user
|
||||
RABBITMQ_DEFAULT_PASS: pass
|
||||
RABBITMQ_DEFAULT_VHOST: vhost
|
||||
healthcheck:
|
||||
test: ["CMD", "rabbitmqctl", "status"]
|
||||
interval: 10s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
Loading…
Add table
Add a link
Reference in a new issue