From 544578a375c5e856ae70247a921871a1b7882445 Mon Sep 17 00:00:00 2001 From: Eduard Marbach Date: Thu, 4 Jun 2026 20:52:47 +0200 Subject: [PATCH 1/2] feat(docker): harden standalone image and add CI Refresh the multi-stage Dockerfile: Maven 3.9 on Temurin 8, non-root owl2vowl user, HEALTHCHECK on /serverTimeStamp. Document how the WebVOWL merged stack consumes this repo as a sibling build context. Adds docker-ci (build + smoke test on PR/master) and docker-release (publish ghcr.io/visualdataweb/owl2vowl on v* tags). Pairs with VisualDataWeb/WebVOWL#218. --- .dockerignore | 5 +++ .github/workflows/docker-ci.yml | 55 ++++++++++++++++++++++++++++ .github/workflows/docker-release.yml | 49 +++++++++++++++++++++++++ Dockerfile | 41 ++++++++++++++++----- README.md | 9 ++--- doc/docker/README.md | 44 ++++++++++++++++++++++ 6 files changed, 189 insertions(+), 14 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/docker-ci.yml create mode 100644 .github/workflows/docker-release.yml create mode 100644 doc/docker/README.md diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c8f5623 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +.git +target +ontologies +*.md +!doc/docker/README.md diff --git a/.github/workflows/docker-ci.yml b/.github/workflows/docker-ci.yml new file mode 100644 index 0000000..3e8177d --- /dev/null +++ b/.github/workflows/docker-ci.yml @@ -0,0 +1,55 @@ +name: Docker CI + +on: + pull_request: + paths: + - ".github/workflows/docker-ci.yml" + - "Dockerfile" + - "pom.xml" + - "src/**" + push: + branches: [master, main] + paths: + - ".github/workflows/docker-ci.yml" + - "Dockerfile" + - "pom.xml" + - "src/**" + +concurrency: + group: docker-ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v6.0.3 + + - uses: docker/setup-buildx-action@v4.1.0 + + - name: Build image + uses: docker/build-push-action@v7.2.0 + with: + context: . + file: Dockerfile + tags: owl2vowl:ci + load: true + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Smoke test + run: | + docker run -d --name owl2vowl-ci -p 8080:8080 owl2vowl:ci + for i in $(seq 1 40); do + if curl -sf http://127.0.0.1:8080/serverTimeStamp; then + echo "OK" + docker rm -f owl2vowl-ci + exit 0 + fi + sleep 3 + done + docker logs owl2vowl-ci + docker rm -f owl2vowl-ci + exit 1 diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml new file mode 100644 index 0000000..a2cf9f0 --- /dev/null +++ b/.github/workflows/docker-release.yml @@ -0,0 +1,49 @@ +name: Docker Release + +on: + push: + tags: + - "v*" + +permissions: + contents: read + packages: write + +env: + REGISTRY: ghcr.io + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6.0.3 + + - uses: docker/setup-buildx-action@v4.1.0 + + - uses: docker/login-action@v4.2.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v6.0.0 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=latest + + - name: Build and push + uses: docker/build-push-action@v7.2.0 + with: + context: . + file: Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile index 68714f9..90e7dff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,40 @@ -FROM maven:3.5.3-jdk-8-slim AS build +ARG OWL2VOWL_VERSION=0.3.7 +ARG MAVEN_IMAGE=3.9.16-eclipse-temurin-8-noble +ARG JRE_IMAGE=8-jre-noble + +FROM maven:${MAVEN_IMAGE} AS build WORKDIR /var/lib/owl2vowl -ADD pom.xml . -RUN ["mvn", "clean"] +COPY pom.xml . +RUN mvn -B dependency:go-offline -P war-release + +COPY src src +RUN mvn -B package -P war-release -DskipTests + +FROM eclipse-temurin:${JRE_IMAGE} -ADD src src -RUN ["mvn", "package", "-DskipTests", "-P", "war-release"] +ARG OWL2VOWL_VERSION=0.3.7 +LABEL org.opencontainers.image.title="OWL2VOWL" \ + org.opencontainers.image.description="OWL to VOWL JSON converter (Spring Boot WAR)" \ + org.opencontainers.image.version="${OWL2VOWL_VERSION}" -FROM java:8-jre-alpine +RUN apt-get update \ + && apt-get install -y --no-install-recommends curl \ + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r owl2vowl --gid=10001 \ + && useradd -r -g owl2vowl --uid=10001 --home-dir=/owl2vowl owl2vowl \ + && mkdir -p /owl2vowl \ + && chown -R owl2vowl:owl2vowl /owl2vowl WORKDIR /owl2vowl -COPY --from=build /var/lib/owl2vowl/target/owl2vowl.war . -CMD java -jar owl2vowl.war +COPY --from=build --chown=owl2vowl:owl2vowl /var/lib/owl2vowl/target/owl2vowl.war . + +USER owl2vowl + +EXPOSE 8080 + +HEALTHCHECK --interval=30s --timeout=5s --start-period=90s --retries=3 \ + CMD curl -f http://127.0.0.1:8080/serverTimeStamp || exit 1 -EXPOSE 8080 \ No newline at end of file +CMD ["java", "-jar", "owl2vowl.war"] diff --git a/README.md b/README.md index 777b27d..f43df6f 100644 --- a/README.md +++ b/README.md @@ -83,11 +83,10 @@ It would be a pain always building the jar only to test some new implemented stu To run a Spring Server directly from the IDE you have to start the `ServerMain.java` class. -### Building docker image -With the provided `Dockerfile` you can easily build the docker image of the server version on the exposed port `8080`. -Just run `docker build -t owl2vowl/owl2vowl .` -After that you can run the image `docker run --rm -d -p 8080:8080 owlv2vowl/owl2vowl`. -OWL2VOWL is now reachable on `localhost:8080`. +### Docker + +- **With WebVOWL (recommended):** clone both repos as siblings; build and run from the WebVOWL directory — see `WebVOWL/docker/README.md`. +- **Standalone converter:** see [doc/docker/README.md](doc/docker/README.md) (`docker build -t owl2vowl:local .`). FAQ diff --git a/doc/docker/README.md b/doc/docker/README.md new file mode 100644 index 0000000..fd4f049 --- /dev/null +++ b/doc/docker/README.md @@ -0,0 +1,44 @@ +# Docker — OWL2VOWL + +## Full stack (WebVOWL + converter) + +OWL2VOWL is built **into** the WebVOWL image. Clone both repositories as **siblings** and run from **WebVOWL**: + +```text +workspace/ + WebVOWL/ + OWL2VOWL/ ← this repo +``` + +```bash +cd ../WebVOWL +docker compose build +docker compose up -d +``` + +Documentation and ADR: `WebVOWL/docker/README.md`, `WebVOWL/docs/adr/0001-docker-local-development.md`. + +Compose references this repo via `additional_contexts.owl2vowl: ../OWL2VOWL`. + +## Standalone converter image (this repo) + +Optional JAR/WAR-only container (no WebVOWL UI): + +```bash +cd OWL2VOWL +docker build -t owl2vowl:local . +docker run --rm -p 8080:8080 owl2vowl:local +``` + +Uses `OWL2VOWL/Dockerfile` (`maven:3.9.16-eclipse-temurin-8-noble` → `eclipse-temurin:8-jre-noble`). Runs as user **`owl2vowl`** (non-root) with `HEALTHCHECK` on `/serverTimeStamp`. + +### CI / GHCR + +| Workflow | Trigger | Image | +|----------|---------|-------| +| `.github/workflows/docker-ci.yml` | PR + `master` | Build + smoke test | +| `.github/workflows/docker-release.yml` | Tag `v*` | `ghcr.io/visualdataweb/owl2vowl` | + +## Build context + +`.dockerignore` excludes `ontologies/` (large sample files) from Docker context when this directory is used as an additional context from WebVOWL. From b7fbefc31d1a939d02c36ae2fd4c2a264d2fd095 Mon Sep 17 00:00:00 2001 From: Eduard Marbach Date: Thu, 4 Jun 2026 21:04:46 +0200 Subject: [PATCH 2/2] docs(docker): WebVOWL clones OWL2VOWL at build time Align README with WebVOWL Dockerfile git clone; no sibling checkout. --- doc/docker/README.md | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/doc/docker/README.md b/doc/docker/README.md index fd4f049..509ae02 100644 --- a/doc/docker/README.md +++ b/doc/docker/README.md @@ -2,23 +2,15 @@ ## Full stack (WebVOWL + converter) -OWL2VOWL is built **into** the WebVOWL image. Clone both repositories as **siblings** and run from **WebVOWL**: - -```text -workspace/ - WebVOWL/ - OWL2VOWL/ ← this repo -``` +OWL2VOWL is built **into** the WebVOWL image. Clone **WebVOWL** only; the Dockerfile clones this repo from GitHub during `docker build`: ```bash -cd ../WebVOWL -docker compose build -docker compose up -d +git clone https://github.com/VisualDataWeb/WebVOWL.git +cd WebVOWL +docker compose build && docker compose up -d ``` -Documentation and ADR: `WebVOWL/docker/README.md`, `WebVOWL/docs/adr/0001-docker-local-development.md`. - -Compose references this repo via `additional_contexts.owl2vowl: ../OWL2VOWL`. +See `WebVOWL/docker/README.md` (build args `OWL2VOWL_GIT_REF`, `OWL2VOWL_GIT_URL`). ## Standalone converter image (this repo) @@ -41,4 +33,4 @@ Uses `OWL2VOWL/Dockerfile` (`maven:3.9.16-eclipse-temurin-8-noble` → `eclipse- ## Build context -`.dockerignore` excludes `ontologies/` (large sample files) from Docker context when this directory is used as an additional context from WebVOWL. +`.dockerignore` excludes `ontologies/` from the standalone image build context.