# Migratieplan: Standaardisatie van Startup Processen en Docker Builds Dit document beschrijft de migratie-afspraken rond het opstarten van onze applicaties, inclusief het gebruik van een generiek startscript, het inzetten van `tini` als entrypoint, en de overstap naar een **shared base build** structuur. Doel: **standaardisatie**, **betere betrouwbaarheid in Kubernetes**, en **snellere builds**. --- ## 1. Generiek startscript (`scripts/start.sh`) ### Doel - Eén startscript voor **alle rollen**: web, worker, beat. - Gedrag wordt bepaald via **environment variables** (`ROLE=web|worker|beat`). - Geen “magische” verschillen meer tussen Podman en Kubernetes. ### Voorbeeld ```bash #!/usr/bin/env bash set -euo pipefail ROLE="${ROLE:-web}" case "$ROLE" in web) exec gunicorn -w "${WORKERS:-1}" -k "${WORKER_CLASS:-gevent}" -b "0.0.0.0:${PORT:-8080}" --worker-connections "${WORKER_CONN:-100}" --access-logfile - --error-logfile - --log-level "${LOGLEVEL:-info}" scripts.run_eveai_app:app ;; worker) exec celery -A scripts.run_eveai_workers worker --loglevel="${CELERY_LOGLEVEL:-INFO}" --concurrency="${CELERY_CONCURRENCY:-2}" --max-tasks-per-child="${CELERY_MAX_TASKS_PER_CHILD:-1000}" --prefetch-multiplier="${CELERY_PREFETCH:-1}" -O fair ;; beat) exec celery -A scripts.run_eveai_workers beat --loglevel="${CELERY_LOGLEVEL:-INFO}" ;; *) echo "Unknown ROLE=$ROLE" >&2 exit 1 ;; esac ``` ### Belangrijk - **Geen init/migraties** meer in het startscript (die draaien we via Jobs/CronJobs). - **Geen `cd`, `chown`, of PYTHONPATH-hacks** in startscript → alles naar Dockerfile. - **Altijd `exec`** gebruiken zodat processen signalen correct ontvangen. --- ## 2. Gebruik van `tini` als ENTRYPOINT ### Waarom? - In containers draait het eerste proces als **PID 1**. - Zonder init-proces worden signalen niet correct doorgegeven en ontstaan **zombieprocessen**. - `tini` is een lichtgewicht init die dit oplost. ### Implementatie ```dockerfile RUN apt-get update && apt-get install -y --no-install-recommends tini && rm -rf /var/lib/apt/lists/* ENTRYPOINT ["/usr/bin/tini","-g","--"] CMD ["bash","-lc","scripts/start.sh"] ``` - `-g` = stuur signalen naar de hele process group (belangrijk voor Gunicorn en Celery). - Hiermee is een apart `entrypoint.sh` niet meer nodig. --- ## 3. Verplaatsen van logica naar Dockerfile ### Wat naar de Dockerfile moet - `WORKDIR /app` - `ENV PYTHONPATH=/app:/app/patched_packages:$PYTHONPATH` - `ENV FLASK_APP=/app/scripts/run_eveai_app.py` (alleen nodig voor CLI, niet voor gunicorn) - User-aanmaak en permissies: ```dockerfile ARG UID=10001 ARG GID=10001 RUN groupadd -g ${GID} appuser && useradd -u ${UID} -g ${GID} -M -d /nonexistent -s /usr/sbin/nologin appuser RUN chown -R appuser:appuser /app USER appuser ``` ### Wat niet meer in startscript hoort - `cd /app` - `export PYTHONPATH=...` - `chown -R ... /logs` - DB-migraties of cache-invalidatie → deze verhuizen naar **Kubernetes Jobs/CronJobs**. --- ## 4. Kubernetes Jobs & CronJobs ### Use cases - **Jobs** → eenmalige taken zoals DB-migraties of cache-invalidatie. - **CronJobs** → geplande taken (bv. nachtelijke opschoningen). ### Waarom? - Startup scripts blijven lean. - Geen race conditions bij meerdere replicas. - Flexibel los van deploys uit te voeren. --- ## 5. Docker builds: naar een shared base (Optie B) ### Nieuwe structuur ``` repo/ ├─ Dockerfile.base ├─ requirements.txt ├─ common/ ├─ config/ ├─ scripts/ ├─ patched_packages/ ├─ docker/ │ ├─ eveai_app/Dockerfile │ ├─ eveai_api/Dockerfile │ └─ eveai_workers/Dockerfile └─ compose_dev.yaml ``` ### Dockerfile.base ```dockerfile FROM python:3.12-slim ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 RUN apt-get update && apt-get install -y --no-install-recommends tini && rm -rf /var/lib/apt/lists/* ARG UID=10001 ARG GID=10001 RUN groupadd -g ${GID} appuser && useradd -u ${UID} -g ${GID} -M -d /nonexistent -s /usr/sbin/nologin appuser WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY common /app/common COPY config /app/config COPY scripts /app/scripts COPY patched_packages /app/patched_packages RUN chown -R appuser:appuser /app && chmod +x /app/scripts/start.sh ENV PYTHONPATH=/app:/app/patched_packages:${PYTHONPATH} ROLE=web PORT=8080 USER appuser EXPOSE 8080 ENTRYPOINT ["/usr/bin/tini","-g","--"] CMD ["bash","-lc","scripts/start.sh"] ``` ### Service Dockerfiles #### docker/eveai_app/Dockerfile ```dockerfile FROM yourorg/eveai-base:py312-v1 WORKDIR /app COPY eveai_app /app/eveai_app COPY migrations /app/migrations COPY content /app/content ENV ROLE=web PORT=8080 ``` #### docker/eveai_api/Dockerfile ```dockerfile FROM yourorg/eveai-base:py312-v1 WORKDIR /app COPY eveai_api /app/eveai_api ENV ROLE=web PORT=8080 ``` #### docker/eveai_workers/Dockerfile ```dockerfile FROM yourorg/eveai-base:py312-v1 WORKDIR /app COPY eveai_workers /app/eveai_workers ENV ROLE=worker ``` --- ## 6. Workflow afspraken 1. **Startscript** is generiek → gedrag via env (`ROLE=...`). 2. **Geen init-taken** meer in startscript → Jobs/CronJobs in k8s. 3. **`tini` als ENTRYPOINT** → correcte signalen en zombie-cleanup. 4. **Dockerfile** regelt PYTHONPATH, FLASK_APP, permissies en user. 5. **Base image** bevat Python, deps en common code. 6. **Service-images** kopiëren enkel hun eigen directories. 7. **Build flow**: - Base builden/pushen bij gewijzigde deps/common. - Services snel erbovenop rebuilden bij code-wijzigingen. --- ## 7. Samenvatting Met deze migratie krijgen we: - Eenvoudiger startscript (alleen proceskeuze). - Betere betrouwbaarheid bij shutdowns (via tini). - Strikte scheiding tussen **lifecycle taken** en **runtime**. - Snellere builds via shared base image. - Uniforme aanpak in zowel Podman/Compose als Kubernetes.