Replace Singularity with Docker; add production deployment setup
- Remove Singularity.def; add Dockerfile (python:3.11-slim + ImageMagick, non-root user, installs gallery package with dev extras) - Add .dockerignore to keep image lean - Rewrite .gitlab-ci.yml: build→test→publish stages using Docker-in-Docker; push per-commit SHA tag and promote to :latest on main - Add docker-compose.yml: gallery-generator + nginx services sharing a named volume; configurable GENERATE_INTERVAL env var - Add deploy/nginx.conf: gzip, security headers, correct caching policy (immutable for assets, no-store for HTML) - Add deploy/entrypoint.sh: runs gallery generate on startup then loops on GENERATE_INTERVAL; exits cleanly when interval is 0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+72
-38
@@ -1,59 +1,70 @@
|
||||
# GitLab CI/CD Pipeline for Gallery Generator
|
||||
# Builds Apptainer container and runs tests inside it
|
||||
# GitLab CI/CD Pipeline for ETPlot
|
||||
# Builds a Docker image and runs tests inside it.
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- publish
|
||||
|
||||
variables:
|
||||
CONTAINER_IMAGE: "gallery-generator.sif"
|
||||
APPTAINER_CACHE_DIR: "$CI_PROJECT_DIR/.apptainer-cache"
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
|
||||
IMAGE_LATEST: $CI_REGISTRY_IMAGE:latest
|
||||
|
||||
# Cache to speed up builds
|
||||
cache:
|
||||
key: "$CI_COMMIT_REF_SLUG"
|
||||
paths:
|
||||
- .apptainer-cache/
|
||||
# ---------------------------------------------------------------------------
|
||||
# Build
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Build the Apptainer container
|
||||
build:container:
|
||||
build:image:
|
||||
stage: build
|
||||
tags:
|
||||
- apptainer
|
||||
image: docker:27
|
||||
services:
|
||||
- docker:27-dind
|
||||
variables:
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
before_script:
|
||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
|
||||
script:
|
||||
- echo "Building Apptainer container..."
|
||||
- apptainer --version
|
||||
- apptainer build --fakeroot $CONTAINER_IMAGE Singularity.def
|
||||
- ls -lh $CONTAINER_IMAGE
|
||||
artifacts:
|
||||
paths:
|
||||
- $CONTAINER_IMAGE
|
||||
expire_in: 1 hour
|
||||
- docker build --pull -t "$IMAGE_TAG" .
|
||||
- docker push "$IMAGE_TAG"
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
|
||||
# Run tests inside the container
|
||||
test:pytest:
|
||||
# ---------------------------------------------------------------------------
|
||||
# Test
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
.test_base:
|
||||
stage: test
|
||||
tags:
|
||||
- apptainer
|
||||
dependencies:
|
||||
- build:container
|
||||
image: docker:27
|
||||
services:
|
||||
- docker:27-dind
|
||||
variables:
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
before_script:
|
||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
|
||||
- docker pull "$IMAGE_TAG"
|
||||
needs:
|
||||
- build:image
|
||||
|
||||
test:pytest:
|
||||
extends: .test_base
|
||||
script:
|
||||
- echo "Running pytest inside container..."
|
||||
- apptainer exec $CONTAINER_IMAGE pytest /src/tests/ -v
|
||||
- docker run --rm -w /app "$IMAGE_TAG" python -m pytest tests/ -v
|
||||
artifacts:
|
||||
when: always
|
||||
expire_in: 30 days
|
||||
|
||||
# Run tests with coverage
|
||||
test:coverage:
|
||||
stage: test
|
||||
tags:
|
||||
- apptainer
|
||||
dependencies:
|
||||
- build:container
|
||||
extends: .test_base
|
||||
script:
|
||||
- echo "Running coverage analysis inside container..."
|
||||
- apptainer exec $CONTAINER_IMAGE pytest /src/tests/ --cov=/src --cov-report=xml --cov-report=term
|
||||
- apptainer exec $CONTAINER_IMAGE cat /src/coverage.xml > coverage.xml || echo "No coverage.xml found"
|
||||
- |
|
||||
docker run --rm -w /app \
|
||||
-v "$CI_PROJECT_DIR:/artifacts" \
|
||||
"$IMAGE_TAG" \
|
||||
python -m pytest tests/ \
|
||||
--cov=gallery \
|
||||
--cov-report=xml:/artifacts/coverage.xml \
|
||||
--cov-report=term
|
||||
coverage: '/TOTAL.*\s+(\d+%)$/'
|
||||
artifacts:
|
||||
reports:
|
||||
@@ -63,3 +74,26 @@ test:coverage:
|
||||
paths:
|
||||
- coverage.xml
|
||||
expire_in: 30 days
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Publish latest tag on main
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
publish:latest:
|
||||
stage: publish
|
||||
image: docker:27
|
||||
services:
|
||||
- docker:27-dind
|
||||
variables:
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
before_script:
|
||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
|
||||
script:
|
||||
- docker pull "$IMAGE_TAG"
|
||||
- docker tag "$IMAGE_TAG" "$IMAGE_LATEST"
|
||||
- docker push "$IMAGE_LATEST"
|
||||
needs:
|
||||
- test:pytest
|
||||
- test:coverage
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
|
||||
Reference in New Issue
Block a user