Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
77baf1d
ref: Rename oidc properties file with .example
RobertGemmaJr Aug 31, 2026
13ae6e6
chore: gitignore
RobertGemmaJr Sep 1, 2026
428fd64
wip: Move the config files
RobertGemmaJr Sep 1, 2026
19353c2
chore: Add a TODO
RobertGemmaJr Sep 1, 2026
140a7f0
chore: Update local compose stack
RobertGemmaJr Sep 1, 2026
c0e75b8
feat: Add the oidc plugin (v1.5.0)
RobertGemmaJr Sep 1, 2026
de844e7
feat: Combine linux installs
RobertGemmaJr Sep 1, 2026
298537d
feat: Handle XNAT_VERSION as a build argument
RobertGemmaJr Sep 1, 2026
181f768
chore: Cleanup healthcheck
RobertGemmaJr Sep 1, 2026
967fc1b
wip: Cleanup provider examples
RobertGemmaJr Sep 1, 2026
727d119
wip: Move k8s files into a nested subdir
RobertGemmaJr Sep 1, 2026
4d33db0
chore: cleanup localhost URL
RobertGemmaJr Sep 1, 2026
4a3940d
docs: Cleanup the Dockerfile
RobertGemmaJr Sep 1, 2026
038611a
chore: cleanup compose file
RobertGemmaJr Sep 1, 2026
6743b4c
wip : Cleanup k8s config
RobertGemmaJr Sep 1, 2026
99d44ce
feat: symlink the config folder to the k8s dir
RobertGemmaJr Sep 1, 2026
ce91967
chore: README
RobertGemmaJr Sep 1, 2026
c789da3
wip: Delete the symlink
RobertGemmaJr Sep 1, 2026
f45882a
ref: Move the env and config setup to the k8s directory
RobertGemmaJr Sep 1, 2026
648709a
chore: README cleanup
RobertGemmaJr Sep 1, 2026
60256f3
wip: Fix local k8s app config
RobertGemmaJr Sep 1, 2026
4eccfc8
wip: More config fixing
RobertGemmaJr Sep 1, 2026
16fc197
ref: Drop xnat.local, just use localhost
RobertGemmaJr Sep 1, 2026
d360362
wip: Configure env seperately
RobertGemmaJr Sep 1, 2026
ab12ede
wip: More env cleanup
RobertGemmaJr Sep 1, 2026
3e3484b
chore: Cleanup healthcheck
RobertGemmaJr Sep 3, 2026
771e482
wip: Copy docker compose stack into a nested subfolder
RobertGemmaJr Sep 8, 2026
2644ab2
wip: Cleanup example properties in the .env files
RobertGemmaJr Sep 8, 2026
db2245f
docs: Work out the split documentation files for the local deployments
RobertGemmaJr Sep 8, 2026
d1c302d
docs: Finish the docker and base documentation
RobertGemmaJr Sep 8, 2026
994cd85
docs: more documentation
RobertGemmaJr Sep 8, 2026
bdb86f5
chore: PR cleanup
RobertGemmaJr Sep 8, 2026
d0f0e30
docs: Little bitts of README cleanup
RobertGemmaJr Sep 8, 2026
76a659f
Update healthcheck URL and options for postgres service
RobertGemmaJr Sep 8, 2026
fbb7b70
Fix typo in README regarding GitHub
RobertGemmaJr Sep 8, 2026
2db9935
chore: PR cleanup
RobertGemmaJr Sep 8, 2026
dd05d64
Merge branch 'oidc' of https://github.com/brown-bnc/xnat into oidc
RobertGemmaJr Sep 8, 2026
1b470b3
chore: More PR cleanup
RobertGemmaJr Sep 8, 2026
35db145
Merge branch 'main' into oidc
RobertGemmaJr Sep 14, 2026
5dd6453
chore: PR cleanup
RobertGemmaJr Sep 14, 2026
edc37f7
Merge branch 'main' into oidc
RobertGemmaJr Sep 14, 2026
07b7639
ref: Keep the .env files in git
RobertGemmaJr Sep 14, 2026
6c3c419
docs: Update readme
RobertGemmaJr Sep 14, 2026
f4bf675
wip: Comment out the OIDC/LDAP data so the deployments work on a fres…
RobertGemmaJr Sep 14, 2026
66dafba
Correct README formatting for plugin installation
RobertGemmaJr Sep 14, 2026
6438b7c
chore: PR cleanup
RobertGemmaJr Sep 14, 2026
7b72b4a
Merge branch 'oidc' of https://github.com/brown-bnc/xnat into oidc
RobertGemmaJr Sep 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
# IDE
.vscode

# Env
.env
ldap.env

# Properties
xnat-conf.properties
*.properties
56 changes: 31 additions & 25 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
#-----------------------------------------------------------------------------
# BUILD
# Build the XNAT web artifact from source
#-----------------------------------------------------------------------------
ARG XNAT_VERSION=1.10.0

###################################################################################################
### BUILD
### Build the XNAT web artifact from source
###################################################################################################
FROM eclipse-temurin:21-jdk AS build

# CAUTION: XNAT VERSION for this stage, make sure to also update next stage!!
ENV XNAT_VERSION=1.10.0
ARG XNAT_VERSION
ENV JAVA_OPTS="-Xmx2560m -XX:+HeapDumpOnOutOfMemoryError"

RUN apt-get update && apt-get install -y \
git

RUN cd /root \
&& git clone --branch "${XNAT_VERSION}" https://bitbucket.org/xnatdev/xnat-web
# Clone the XNAT repository
RUN apt-get update && apt-get install -y git
WORKDIR /root
RUN git clone --branch "${XNAT_VERSION}" https://bitbucket.org/xnatdev/xnat-web

# Build XNAT
WORKDIR /root/xnat-web
RUN ./gradlew --no-daemon clean war

#-----------------------------------------------------------------------------
# APPLICATION
# Runs the XNAT web application
#-----------------------------------------------------------------------------
###################################################################################################
### APPLICATION
### Runs the XNAT web application
###################################################################################################
FROM tomcat:9-jdk21-temurin

ENV XNAT_VERSION=1.10.0
ARG XNAT_VERSION

RUN apt-get update && apt-get install -y --no-install-recommends \
libfreetype6 \
fontconfig \
fonts-dejavu-core \
&& rm -rf /var/lib/apt/lists/*

RUN apt-get update && apt-get install -y \
curl \
unzip \
&& rm -rf /var/lib/apt/lists/*

# Create data directories
RUN mkdir -p \
/data/xnat/archive \
/data/xnat/build \
Expand All @@ -52,31 +51,38 @@ RUN mkdir -p \
/data/xnat/prearchive \
/data/xnat/dicom-export

VOLUME ["/data/xnat/home/config", "/data/xnat/home/config/auth"]
# Copy built files
COPY --from=build "/root/xnat-web/build/libs/xnat-web-${XNAT_VERSION}.war" \
"${CATALINA_HOME}/webapps/ROOT.war"
# Copy local files
COPY docker-entrypoint.sh "/usr/local/bin/docker-entrypoint.sh"

COPY --from=build "/root/xnat-web/build/libs/xnat-web-${XNAT_VERSION}.war" "${CATALINA_HOME}/webapps/ROOT.war"
# Unpack WAR file for tomcat
RUN mkdir -p "${CATALINA_HOME}/webapps/ROOT" \
&& cd "${CATALINA_HOME}/webapps/ROOT" \
&& jar xf ../ROOT.war \
&& rm ../ROOT.war

# Install LDAP and XSYNC plugins. The versions need to be compatible with the version of XNAT

# Install plugins
# !CAUTION: Ensure these versions are compatible with the current version of XNAT
RUN cd /data/xnat/home/plugins \
# Authentication Plugins
&& curl -fLO "https://bitbucket.org/xnatx/ldap-auth-plugin/downloads/ldap-auth-plugin-1.3.0.jar" \
&& curl -fLO "https://bitbucket.org/xnatx/openid-auth-plugin/downloads/openid-auth-plugin-1.5.0-xpl.jar" \
# Imaging & Workflow Plugins
&& curl -fLO "https://xnat.org/files/ohif-viewer-xnat-plugin/ohif-viewer-3.8.0-fat.jar" \
&& curl -fLO "https://bitbucket.org/xnatdev/dicom-query-retrieve/downloads/dicom-query-retrieve-3.0.0-xpl.jar" \
&& curl -fLO "https://bitbucket.org/xnatx/pipeline_engine_plugin/downloads/pipeline_engine_ui-1.2.0-xpl.jar" \
&& curl -fLO "https://bitbucket.org/xnatdev/container-service/downloads/container-service-3.8.1-fat.jar" \
&& curl -fLO "https://github.com/NrgXnat/batch-transfer-plugin/releases/download/v1.1.1/batch-transfer-1.1.1.jar" \
&& curl -fLO "https://bitbucket.org/xnatx/xnatx-batch-launch-plugin/downloads/batch-launch-0.9.0-xpl.jar"

COPY docker-entrypoint.sh "/usr/local/bin/docker-entrypoint.sh"


# NOTE (BNR): Ports have the following use:
# 8000 - Catalina debug port, only used if debug is set to true
# 8080 - Web port, this is how users connect to XNAT
# 8104 - Scanner port, this is how the scanner connects to XNAT
EXPOSE 8000/tcp 8080/tcp 8104/tcp

ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["run"]
162 changes: 35 additions & 127 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,149 +1,57 @@
# XNAT Cluster
# XNAT

This repository contains the files necessary to build, and test-deploy Brown
University's instance of XNAT to the SciDMZ cluster.
> [!IMPORTANT]
> XNAT requires Apache Tomcat 9, JDK 21, and PostgreSQL 12 or later. Tomcat 10 and newer are not supported.

The `Dockerfile` builds XNAT as it's used at Brown University.
This repository contains the files necessary to build Brown University's instance of XNAT and deploy it locally.

XNAT requires Apache Tomcat version 9, JDK 1.8, and Postgresql 10. No other
versions are supported.
- The [Dockerfile](./Dockerfile) builds XNAT as it's used at Brown University
- The [docker/](./docker/) files deploy the image locally using Docker Compose
- The [k8s/](./k8s/) files deploy the image locally using Kubernetes

This repository provides two ways of running development versions of XNAT,
via Docker Compose or Kubernetes. Neither the `kustomization.yaml` nor the `docker-compose.yaml` provided in this repository are used in production. They were used only for testing purposes.
Our deployment of the production instance in done via kubernetes and managed in [this repo](https://github.com/brown-ccv/k8s-deploy-bke)
## Plugin Support

## Routine updates and GitHub Actions
>[!WARNING]
> Plugin versions must be compatible with the XNAT version being built. Update versions in the [Dockerfile](./Dockerfile) when upgrading XNAT.

There is a GitHub Action that builds the `Dockerfile`. After merging to the `main` branch, please tag a new release. The release name will be used as the tag for the image. The practice is to align with the version of xnat being used. For instance, release number 1.8.4, meanse we used XNAT version 1.8.4. If a patch is needed on our image for an already tagged version, just spell the patch. For instance `1.8.4-OIFH-plugin`
XNAT plugins are installed directly into the Docker image during build time. The [Dockerfile](./Dockerfile) installs the plugins towards the end of the file.

## Manual building/testing
### Authentication Plugins

Typically not necessary, unless you are just learning how all of this works. We have a QA environment for testing in [this repo](https://github.com/brown-ccv/k8s-deploy-bke)
>[!TIP]
> For more details on setting up custom auth providers, see [XNAT's documentation](https://wiki.xnat.org/documentation/configuring-authentication-providers).

### Building the Docker image
The authentication providers available to users for logging into the portal. Each provider's properties file must be mounted in the `/data/xnat/home/config/auth` directory.

The `docker-compose.yaml` file contains the necessary information to build
the Docker image. There is one argument to the Docker image build,
`$XNAT_VERSION`. The `Dockerfile` leverages a multi-stage build process
that clones the `xnat-web` repository and builds from source. The version
of `xnat-web` cloned depends on `$XNAT_VERSION`. `$XNAT_VERSION` may be a
tag or branch.
- **[LDAP](https://wiki.xnat.org/xnat-tools/xnat-ldap-authentication-plugin):** Authenticates users against an external LDAP directory
- **[OpenID](https://wiki.xnat.org/xnat-tools/openid-authentication-plugin):** Authenticates users through OIDC identity providers

To build the Docker image run:
### Imaging & Workflow Plugins

```shell
docker-compose build
```
- **[OHIF Viewer](https://wiki.xnat.org/xnat-ohif-viewer):** Web viewer for DICOM images within XNAT
- **[DICOM Query/Retrieve](https://wiki.xnat.org/xnat-tools/dicom-query-retrieve-plugin):** Queries and pulls studies from remote DICOM nodes via C-FIND and C-MOVE
- **[Container Service](https://wiki.xnat.org/container-service):** Runs containerized processing pipelines against XNAT data
- **[Pipeline Engine UI](https://wiki.xnat.org/xnat-tools/xnat-pipeline-engine-plugin):** Web interface for configuring and launching XNAT's pipeline engine
- **[Batch Transfer](https://github.com/NrgXnat/batch-transfer-plugin/blob/main/README.md):** Uploads and transfers imaging sessions to XNAT in bulk

### Docker Compose
## Image Versioning and Releases

To start the compose stack run:
The [docker-build-push](./.github/workflows/docker-build-push.yaml) action builds the XNAT application and pushes it to GitHub Container Registry.

```shell
docker-compose up
```
A new release should be created in GitHub in order to resolve the correct version of XNAT in GHCR. This should be done after every PR is merged into the `main` branch!

### Kubernetes
The name of the release will be used as the tag for the image and should align with the version of XNAT being used. For instance, if the current version of XNAT is `1.8.4` then the name of the release should be `1.8.4`. If a patch must be applied to an already tagged image then the name of the patch should postfix the release number. For instance, `1.8.4-OIFH-plugin` adds the `OIFH-plugin` to XNAT version `1.8.4`.

First you must install minikube. See [this guide][1] for more details. I
used `brew` on macOS to install minikube. Once minikube is installed, start
it with the following command.
## Local Deployments

Kubernetes version can be omitted, but I like to keep it there to make
sure my manifests are compatible with my clusters. Make sure the driver
you use matches your system configuration, and can support the nginx
ingress controller.
>[!NOTE]
> The XNAT deployments running on Brown University's infrastructure (staging, QA, and production) are managed via Kubernetes in the [k8s-deploy-bke](https://github.com/brown-ccv/k8s-deploy-bke) repository. The methods listed below are intended solely for local, test deployments.

```shell
minikube start --kubernetes-version=v1.18.10 --driver=hyperkit
```
The Docker and K8s folders provide some configuration files that automatically initialize the XNAT application.

Once minikube has started, enable the ingress controller if you haven't
already.
- The [docker](./docker/) folder contains files and instructions for building and deploying the XNAT application locally using Docker Compose. Additional details can be found in [DOCKER.md](./docker/DOCKER.md).
- The [k8s](./k8s/) folder contains files and instructions for building and deploying the XNAT application locally using Kubernetes. Additional details can be found in [K8S.md](./k8s/K8S.md).

```shell
minikube addons enable ingress
```
### Authentication Providers

To run the Kubernetes deployment run:

```shell
kubectl apply -k .
```

This will set up XNAT with all the fixings including a local database.
`app.yaml` contains the manifests related to XNAT, `db.yaml` contains the
manifests for the database.

By default XNAT is configured as a `ClusterIp` service, meaning that XNAT
does not expose any external addresses. There are three ways to connect to
XNAT: Kubernetes port-forwarding, curl, and `/etc/hosts`.

Kubernetes offers a method of forwarding traffic to and from the cluster.
With this we can proxy traffic to a service running inside the cluster.

```shell
kubectl port-forward svc/xnat 8080:80
```

This command will forward `localhost:8080` traffic to the XNAT service
within the Kubernetes cluster. From there the service will forward the
traffic to the deployment.

If you want a quick sanity check, curl works great. The following command
forces curl to resolve the address `xnat.local` to your minikube IP
address. `xnat.local` is the name set up by the Kubernetes ingress, see
`app.yaml` for more details.

```shell
curl -vL --resolve xnat.local:80:$(minikube ip) http://xnat.local
```

Lastly, if you're doing prolonged testing with XNAT you can update your
hosts file to point `xnat.local` to your minikube IP address. This is
basically what we did with the previous curl command, but permanent.

```shell
sudo sh -c "echo $(minikube ip) xnat.local >> /etc/hosts"
```

After updating your hosts file you should be able to use `xnat.local` to
access your development XNAT deployment.

## LDAP

Multiple unique LDAP providers are supported. Each LDAP authentication
properties file must be mounted in the `/data/xnat/home/config/auth`
directory. The process varies depending on whether or not you're deploying
with Kubernetes or Docker Swarm.

If deploying with Kubernetes, the LDAP authentication properties files may
be specified as either a `ConfigMap` or `Secret` object. The `ConfigMap` or
`Secret` must then be referenced as a volume, and mounted in the container.

If deploying with Docker Swarm, add the LDAP authentication properties
files as a volume at `/data/xnat/home/config/auth` in the Docker container.

Examples are provided for both Kubernetes and Docker Swarm. Uncomment the
LDAP sections in `app.yaml` and `kustomization.yaml` for Kubernetes.
Uncomment the LDAP section in `docker-compose.yaml` for Docker Swarm.

For an example of an LDAP provider configuration file, see `ldap-provider.properties.example`.

For more details on setting up custom auth providers, see [XNAT's documentation](https://wiki.xnat.org/documentation/configuring-authentication-providers).

## Automatic Initialization

If you want to skip the initialization page on first launch, provide both
`$XNAT_SITE_URL` and `$XNAT_ADMIN_EMAIL` when starting XNAT. The default
username/password will still be `admin:admin`. If you've provided an LDAP
configuration, the automatic initialization will enable your LDAP provider.

## Manual Configuration

You do not have to rely on the config generation rules detailed above to
configure XNAT. `/data/xnat/home/config` is exposed as a volume. You may
add your custom configs in that directory using the standard volume mount
mechanisms of Kubernetes or Docker Swarm. An example is not provided.

[1]: https://minikube.sigs.k8s.io/docs/start/
Instructions for setting up LDAP and OIDC authentication providers are provided for both the [docker](./docker/DOCKER.md#authentication-providers) and [k8s](./k8s/K8S.md#authentication-providers) deployments.
73 changes: 0 additions & 73 deletions app.yaml

This file was deleted.

Loading