Implement per-job Docker-in-Docker (DinD) for E2E tests, giving each job a completely isolated Docker daemon and network. This prevents leakage to the host Docker or other containers. The previous E2E approach failed because: 1. The Forgejo runner's container.docker_host was not set, causing the runner itself to try unix:///var/run/docker.sock and crash-loop. 2. The host DinD daemon had isolated networking — job containers running docker compose could not resolve 'dind' hostname or access host filesystem bind mounts (e.g. .:/app). New approach — zero bind mounts, all COPY-based images: - docker/backend.e2e.Dockerfile: multi-stage build from repo root. Copies gradlew + settings.gradle + backend/build.gradle to download dependencies in a cacheable layer, then copies backend/src and builds the bootJar. Runs the JAR directly on startup. - docker/frontend.e2e.Dockerfile: multi-stage Node build → nginx. Reuses existing docker/nginx.conf for /api proxy to backend service. No volume mounts, fully self-contained. - docker/playwright.e2e.Dockerfile: extends official Playwright image. Installs deps from package-lock.json, copies e2e tests + config. - docker-compose.e2e.yml: zero bind mounts. Services depend on each other in order: postgres (healthy) → backend → frontend → playwright. Playwright waits for backend and frontend via curl loops before running tests. - .forgejo/workflows/ci.yml: E2E job adds a 'dind' service container (docker:28-dind, privileged, no TLS). The job sets DOCKER_HOST to tcp://dind:2375 so the docker CLI inside the job talks to the per-job DinD daemon. The compose file is docker-compose.e2e.yml. - Runner fix on tocke: added container.docker_host: 'tcp://dind:2375' to runner-config.yaml so the runner's own Docker client connects to the host DinD container, stopping the crash loop. Key properties: - Network isolation: each E2E job gets its own DinD with its own container network. No host container visibility. - No bind mount leakage: all images use COPY instead of volume mounts. The per-job DinD has its own filesystem and can't see host paths. - Deterministic: builds start from clean state every time. Image cache exists only within the per-job DinD lifetime. - Lint-and-test job is untouched and remains green.
12 lines
317 B
Docker
12 lines
317 B
Docker
FROM node:24-alpine AS builder
|
|
WORKDIR /app
|
|
COPY frontend/package.json frontend/package-lock.json ./
|
|
RUN npm ci
|
|
COPY frontend/ .
|
|
RUN npm run build
|
|
|
|
FROM nginx:alpine
|
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
|
|
EXPOSE 80
|
|
CMD ["nginx", "-g", "daemon off;"]
|