diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml new file mode 100644 index 00000000..51625730 --- /dev/null +++ b/.github/workflows/container.yml @@ -0,0 +1,39 @@ +name: Container Image + +on: + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v4 + + - name: Set up Java 25 + uses: actions/setup-java@v4 + with: + java-version: '25' + distribution: 'temurin' + cache: 'maven' + + - name: Build and push container image + run: > + mvn -B package -DskipTests + -Dquarkus.container-image.build=true + -Dquarkus.container-image.push=true + -Dquarkus.container-image.tag=latest + -Dquarkus.container-image.username=${{ github.actor }} + -Dquarkus.container-image.password=${{ secrets.GITHUB_TOKEN }} + + - name: Clean up old untagged container versions + uses: actions/delete-package-versions@v5 + with: + package-name: h5m + package-type: container + delete-only-untagged-versions: true + min-versions-to-keep: 0 diff --git a/docs/site/content/en/docs/deployment/docker.md b/docs/site/content/en/docs/deployment/docker.md index e022ed87..96632065 100644 --- a/docs/site/content/en/docs/deployment/docker.md +++ b/docs/site/content/en/docs/deployment/docker.md @@ -5,61 +5,23 @@ description: Running h5m in a Docker container. draft: false --- -{{< alert color="warning" >}} -h5m does not currently publish an official Docker image. The examples on this page show how to build and run your own container image using standard Quarkus patterns. -{{< /alert >}} +## Container Image -## Build the JAR First +A container image is published to GitHub Container Registry on every push to `main`: ```bash -git clone https://github.com/hyperfoil/h5m.git -cd h5m -mvn clean package -``` - -## Create a Dockerfile - -Place this `Dockerfile` in the project root: - -```dockerfile -FROM eclipse-temurin:21-jre - -WORKDIR /app - -COPY target/h5m.jar /app/h5m.jar - -# Data directory for SQLite database -RUN mkdir -p /data && \ - useradd -r -u 1001 h5m && \ - chown h5m:h5m /data - -USER 1001 - -EXPOSE 8080 - -ENV QUARKUS_DATASOURCE_DB_KIND=sqlite -ENV QUARKUS_DATASOURCE_JDBC_URL=jdbc:sqlite:/data/h5m.db - -ENTRYPOINT ["java", "-jar", "/app/h5m.jar"] -``` - -## Build the Image - -```bash -docker build -t h5m:latest . +docker pull ghcr.io/hyperfoil/h5m:latest ``` -## Run with SQLite (Persistent Volume) +Alternatively, build locally using Quarkus JIB (no Docker daemon required): ```bash -docker run -d \ - --name h5m \ - -p 8080:8080 \ - -v h5m-data:/data \ - h5m:latest +git clone https://github.com/hyperfoil/h5m.git +cd h5m +mvn clean package -DskipTests -Dquarkus.container-image.build=true ``` -Data persists in the `h5m-data` Docker volume between restarts. +All examples below work with both Docker and Podman. ## Run with PostgreSQL @@ -71,7 +33,7 @@ docker run -d \ -e QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://db:5432/h5m \ -e QUARKUS_DATASOURCE_USERNAME=h5m \ -e QUARKUS_DATASOURCE_PASSWORD=secret \ - h5m:latest + ghcr.io/hyperfoil/h5m:latest ``` ## Docker Compose @@ -81,7 +43,7 @@ A minimal Compose file with h5m and PostgreSQL: ```yaml services: db: - image: postgres:16 + image: postgres:18 environment: POSTGRES_USER: h5m POSTGRES_PASSWORD: secret @@ -94,7 +56,7 @@ services: retries: 5 h5m: - image: h5m:latest + image: ghcr.io/hyperfoil/h5m:latest ports: - "8080:8080" environment: @@ -116,6 +78,20 @@ Start with: docker compose up -d ``` +## Health Checks + +h5m includes SmallRye Health endpoints for readiness and liveness probes: + +- `GET /q/health/ready` -- returns 200 when the application is ready to serve requests +- `GET /q/health/live` -- returns 200 when the application is alive + +For Testcontainers: + +```java +new GenericContainer<>("ghcr.io/hyperfoil/h5m:latest") + .waitingFor(Wait.forHttp("/q/health/ready").forStatusCode(200)) +``` + ## With OIDC Pass OIDC environment variables at runtime: @@ -133,16 +109,7 @@ docker run -d \ -e QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://db:5432/h5m \ -e QUARKUS_DATASOURCE_USERNAME=h5m \ -e QUARKUS_DATASOURCE_PASSWORD=secret \ - h5m:latest -``` - -## Health Check - -Add a Docker health check to detect startup failures: - -```dockerfile -HEALTHCHECK --interval=10s --timeout=3s --retries=5 \ - CMD curl -f http://localhost:8080/api/folder || exit 1 + ghcr.io/hyperfoil/h5m:latest ``` ## Kubernetes @@ -166,7 +133,7 @@ spec: spec: containers: - name: h5m - image: h5m:latest + image: ghcr.io/hyperfoil/h5m:latest ports: - containerPort: 8080 env: @@ -186,12 +153,12 @@ spec: key: password livenessProbe: httpGet: - path: /api/folder + path: /q/health/live port: 8080 initialDelaySeconds: 15 readinessProbe: httpGet: - path: /api/folder + path: /q/health/ready port: 8080 initialDelaySeconds: 10 ``` diff --git a/pom.xml b/pom.xml index fe6640d4..2303db1f 100644 --- a/pom.xml +++ b/pom.xml @@ -150,6 +150,10 @@ io.quarkus quarkus-arc + + io.quarkus + quarkus-container-image-jib + io.quarkus quarkus-hibernate-orm @@ -194,6 +198,10 @@ io.quarkus quarkus-rest-jsonb + + io.quarkus + quarkus-smallrye-health + io.quarkus quarkus-smallrye-openapi diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index dcdaf1b8..e58ff8b7 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -98,3 +98,10 @@ quarkus.mailer.mock=true %test.h5m.slack.api.url=http://localhost:19876/api/chat.postMessage h5m.slack.api.url=https://slack.com/api/chat.postMessage + +# Container image (JIB) — built via mvn package -Dquarkus.container-image.build=true +quarkus.container-image.group=hyperfoil +quarkus.container-image.name=h5m +quarkus.container-image.registry=ghcr.io +# Default to not building images during normal mvn package +quarkus.container-image.build=false